C++數據結構:B樹

目錄

一.?常見的搜索結構

二. B樹的概念

三. B樹節點的插入和遍歷

3.1?插入B樹節點

3.2 B樹遍歷

四. B+樹和B*樹

4.1 B+樹

4.2 B*樹

五. B樹索引原理

5.1?索引概述

5.2 MyISAM

5.3 InnoDB

六.?總結


一.?常見的搜索結構

表示1為在實際軟件開發項目中,常用的查找結構和方法,包括順序查找、二分查找、二叉搜索樹、平衡二叉樹、哈希表等,這幾種查找方法和數據結構,都適合于內查找(將數據加載到內存中查找)。

搜索結構數據要求時間復雜度
順序查找無要求O(N)
二分查找順序排序O(logN)
二叉搜索樹無要求O(N)
平衡二叉樹無要求O(logN)
哈希表無要求O(1)

如果數據量極大,內存無法存放時,就需要將數據存儲在磁盤當中,而CPU訪問磁盤的速度要遠遠低于訪問內存的速度,假設O(1)的時間復雜度下要執行2次訪問,O(logN)的時間復雜度下要執行30次訪問。如果對內存數據進行訪問,因為訪問內存速度相對較快,所有我們可以認為O(1)和O(logN)時間復雜度算法的性能是一致的。但是如果是對于磁盤上的數據的訪問,由于磁盤數據訪問的效率較低,因此O(1)和O(logN)差別會很大。

采用二叉搜索樹檢索磁盤數據的缺陷為:

  • 二叉搜索樹查找的時間復雜度為O(logN),磁盤IO效率低,O(logN)的時間復雜度相對于O(1)會很大程度上降低性能。

但是,哈希查找的時間復雜度是O(1),為什么哈希也不適用于對磁盤數據的檢索呢?這是因為哈希的有這樣的缺陷:

  • 在極端情況下,哈希表中會產生大量的哈希沖突,查找的時間復雜度會接近O(N)。
  • 雖然很多時候當哈希沖突達到一定數量時,在哈希散列中會由掛單鏈表改為掛紅黑樹,但紅黑樹查找的時間復雜度依舊是O(logN)。

為了解決平衡二叉樹和哈希表無法很好的應對內存數據查找的情況,B樹被創造和出來,B樹適用于對磁盤中大量的數據進行檢索,當然B樹也能夠在內存在查找數據,但效果就不如哈希和平衡二叉樹。

由于B樹/B+樹適用于檢索磁盤中大量數據的性質,經常被用于作為數據庫的底層檢索結構。

二. B樹的概念

B樹是一種適合外查找的平衡多叉樹,一顆m階的B樹,是一顆m路的二叉搜索樹,一顆B樹要么為空樹,要么滿足如下幾個條件:

  1. 根節點至少有兩個孩子節點。
  2. 分支節點(非葉子節點)應當有K-1個鍵值和K個孩子節點,其中ceil(m/2)\leqslant K\leqslant M,其中ceil為向上取整函數。
  3. 所有葉子節點都在同一層。
  4. 每個節點中的鍵值都是自小到大升序排序的,鍵值Key表示子樹的閾值劃分。
  5. 對于任意一個節點,孩子節點的數目總是比鍵值多一個。

圖2.1就是一顆3階B樹,注意觀察其根節點,兩個鍵值為50和100,根節點的第一個孩子節點鍵值全部小于50,第二個孩子節點的鍵值位于(51,100)之間,第三個孩子節點鍵值大于100,這就是鍵值Key的閾值劃分功能。

B樹檢索與二叉搜索樹的檢索類似,假設我們要在圖2.1所示的B樹中檢索99,先從根節點開始找起,對比待查找的值和鍵值的大小,發現其位于(50,100)范圍內,這樣就向下遍歷查找p2子樹,在p2子樹的鍵值中找到了鍵值99,檢索完成。

圖2.1 3階B樹

三. B樹節點的插入和遍歷

3.1?插入B樹節點

由于B樹的插入操作過于抽象,因此直接上實例,在示例中講解B樹節點插入的具體操作。假設依次將std::vector<int> v = { 53,139,75,49,145,36,50,47,101}插入到3階B樹中。為了方便插入操作,我們在申請B樹節點空間的時候,階數為M,就為鍵值申請M個空間,為孩子節點申請M+1個空間,這樣做的目的是方便插入時數據挪動,以及后面的分裂操作

① 插入53

53是B樹插入的第一個節點,因此直接將其插入到根節點的第一個鍵值位置處即可。如果3.1所示,插入53后,有一個B樹根節點,這個根節點附帶有兩個孩子節點nullptr。這里的根節點也是葉子節點,注意B樹插入新節點一定是向葉子節點插入的。

圖3.1?插入B樹的第一個節點53

②?插入139

139大于53,且插入后根節點(葉子結點)中鍵值的數目不超過M-1,因此只需將139至于53的后面,并且帶入null子節點即可。

圖3.2?插入第二個節點139后的B樹結構

③ 插入75

75位于53和139之間,所以第一步要現將75插入到root節點的這兩個值之間。但是,插入75后root節點就有了3個鍵值,這樣就不符合B樹的結構要求,需要進行分裂。

分裂操作的步驟為:

  1. 取中間位置mid = M/2下標處為分界線,創建一個兄弟節點brother,將下標位于[mid+1,M)的鍵值及其左右孩子都拷貝到brother節點中去(設下標為鍵值相同的孩子節點為左孩子,比鍵值下標大1的孩子節點稱為右孩子)。
  2. 將mid處的鍵值交給其父親節點,如果沒有父親節點節創建父親節點,父親節點的其中兩個孩子節點就包含原先發生分裂的節點以及分裂出的節點brother。
圖3.3?插入第三個節點75后的結構及B樹的分裂操作

④?插入49

首先檢索節點插入的位置,發現49小于根節點root的第一個鍵值,因此找到n1節點,n1節點為葉子節點可以執行插入操作,49小于第一個節點53,所以應當將53向后移動一位并將49設置為n1節點的第一個鍵值。

圖3.4?插入B樹第四個節點49

?⑤?插入145

首先檢索插入數據的葉子節點,根節點只有一個鍵值75,145大于75,向n2節點查找,n2為葉子節點可以執行插入操作,將145插入到139后面,插入過后鍵值個數少于階數M,不用分裂。

圖3.5?插入B樹第五個節點49

⑥?插入36

查找36的插入位置應該為圖3.5中的n1節點,將35插入n1后n1有3個鍵值需要進行分裂,兄弟節點取走53,49向上交給n1的父親節點,分裂出的兄弟節點要作為root節點的一個孩子節點。

圖3.6?插入新節點36及分裂操作

⑦?插入50?

直接找到n2節點,插入到鍵值53之前即可。

圖3.7?插入新節點53

⑧?插入47

?插入到n1節點46的后面即可。

圖3.8?插入新節點47

⑨?插入101

先初步執行插入操作,即101插入到n3節點的第一個鍵值位置處,插入后n3節點的鍵值數量達到了階數M,要執行分裂操作。然而分裂后將mid處鍵值交給父親節點(root)管理后,root的鍵值數量也達到了階數M,需要進一步分裂,更新root。

圖3.9?插入新節點101

3.2 B樹遍歷

B樹是一種特殊的搜索樹,如果按照中選遍歷,那么理應得到升序的一組數據,B樹遍歷的方法與普通的二叉搜索樹中序遍歷并沒有本質區別,區別在于M路遍歷和雙路遍歷。圖3.10為二叉搜索樹的遍歷流程圖,遍歷得到升序排序結果。

圖3.10 B樹前序遍歷的遞歸路徑圖

代碼3.1:插入B樹節點和前序遍歷B樹

#include <iostream>// B樹節點,K為索引數據類型,M為最大階數
template<class K, size_t M>
struct BTreeNode
{// 存儲鍵值和孩子節點的一維數組// K _key[M - 1];// BTreeNode<K, M> _sub[M];// 為了方便后續的分裂和插入操作,多開辟一個空間K _key[M];BTreeNode<K, M>* _sub[M + 1];BTreeNode<K, M>* _parent;   // 父親節點size_t _n;   // 鍵值個數// 構造函數BTreeNode(): _parent(nullptr), _n(0){// 鍵值全部清零,孩子節點全部為空for (size_t i = 0; i < M; ++i){_key[i] = K();_sub[i] = nullptr;}_sub[M] = nullptr;}
};template<class K, size_t M>
class BTree
{typedef BTreeNode<K, M> Node;   // B樹節點類型重定義
public:// 插入位置查找函數std::pair<Node*, int> Find(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){// 在本層中,查找大于key的鍵值,如果找到這樣的鍵值或者走到了最后一個鍵值// 那么就到下一層去查找,如果找到與key相同的鍵值,那么就直接返回該位置對應pairsize_t i = 0;while (i < cur->_n){// 鍵值按照升序排序,逐個向后查找即可if (key > cur->_key[i]) {++i;}else if (key < cur->_key[i]){break;}else   // 存在相等就直接返回{return std::make_pair(cur, i);}}parent = cur;cur = cur->_sub[i];}return std::make_pair(parent, -1);}// 在一個B樹節點值插入新鍵值的函數void InsertKey(Node* parent, const K& key, Node* child){int end = parent->_n - 1;while (end >= 0){if (parent->_key[end] > key){// 將大于key的鍵值及其對應的右孩子節點全部向后移動一位parent->_key[end + 1] = parent->_key[end];parent->_sub[end + 2] = parent->_sub[end + 1];--end;}else{break;}}// 將新的key值插入到end+1位置處,并引入右孩子節點parent->_key[end + 1] = key;parent->_sub[end + 2] = child;++parent->_n;}// 新節點(鍵值)插入函數bool Insert(const K& key){// 特殊情況:當前B樹根節點為空,插入的是第一個節點if (_root == nullptr){_root = new Node;_root->_key[0] = key;_root->_n++;return true;}// 查找要插入節點的位置std::pair<Node*, int> ret = Find(key);// 如果對應ret.second>=0,那說明key已經在B樹中存在// B樹不允許冗余,因此直接返回falseif (ret.second >= 0){return false;}Node* parent = ret.first;Node* child = nullptr;K newKey = key;// 向上插入,滿足條件就分裂while (true){InsertKey(parent, newKey, child);if (parent->_n <= M - 1){return true;}else   // 需要進行分裂操作{size_t mid = M / 2;   // 中間節點// 將中間mid之后的鍵值全部交給新創建的brother節點Node* brother = new Node;size_t j = 0;for (size_t i = mid + 1; i < M; ++i){// 將key及其左孩子交給brother節點brother->_key[j] = parent->_key[i];brother->_sub[j] = parent->_sub[i];// 如果左孩子節點不為空,那么就要跟新其父親為brotherif (parent->_sub[i] != nullptr){parent->_sub[i]->_parent = brother;}// 將parent節點中被挪走的key和sub清空parent->_key[i] = K();parent->_sub[i] = nullptr;++j;}// 將最后一個右孩子節點插入到brother節點中brother->_sub[j] = parent->_sub[M];if (parent->_sub[M] != nullptr){parent->_sub[M]->_parent = brother;}parent->_sub[M] = nullptr;// 更新鍵值個數,這里parent鍵值個數減去brother->_n + 1,+1是因為要把mid子節點交給父節點brother->_n = j;parent->_n -= (brother->_n + 1);K midKey = parent->_key[mid];parent->_key[mid] = K();if (parent == _root){_root = new Node;_root->_key[0] = midKey;_root->_sub[0] = parent;_root->_sub[1] = brother;parent->_parent = _root;brother->_parent = _root;_root->_n++;return true;}else{newKey = midKey;parent = parent->_parent;brother->_parent = parent;child = brother;}}}return true;}void _InOrder(Node* root){if (root == nullptr){return;}// 依次遍歷每個節點的左孩子for (size_t i = 0; i < root->_n; ++i){_InOrder(root->_sub[i]);std::cout << root->_key[i] << " ";}// 遍歷最后一個右孩子節點_InOrder(root->_sub[root->_n]);}// 中序函數void InOrder(){// 子函數_InOrder(_root);}private:Node* _root = nullptr;
};

四. B+樹和B*樹

4.1 B+樹

B+樹是在B樹上優化了的多路平衡搜索二叉樹,相比于B樹,B+樹進行了以下幾點優化:

  1. 每個節點的鍵值數量和孩子節點數量相同。
  2. 孩子節點指針p[i]指向的子B樹鍵值范圍位于 [ k[i], k[i+1] ) 之間。
  3. 所有存儲了有效鍵值的節點都在葉子節點上。
  4. 所有葉子節點都被連接了起來。
圖4.1 B+樹的結構

B+樹的節點插入,與B樹類似,同樣由于其過于抽象,本文以具體的實例來展示B+樹節點插入的過程,假設要將std::vector<int> v = { 53,139,75,49,145,36,101 }插入到階數M=3的B+樹中去,插入的流程及操作如下:

①?插入53

插入的第一個節點,首先創建兩層B+樹節點,一層為根節點,一層為葉子節點,在根節點和葉子節點的第一個鍵值位置處,插入元素53。和B樹一樣,如果階數為M,就為鍵值和孩子節點都多開辟一個空間,以方便數據挪到和節點分裂。

圖4.2?向B+樹中插入第一個數據

②?插入139

首先檢索插入位置,發現139大于根節點中唯一一個鍵值53,因此向下遍歷找到n1,將新數據插入到53后面,節點中鍵值個數尚未達到階數,不需要分裂。

圖4.3?向B+樹中插入139

③?插入75

檢索到75應該插入子節點n1中,139向后挪一個單位,75插入到53和139之間,以保證鍵值升序。

圖4.4?向B+樹中插入75

④?插入49

首先查找可以插入49的葉子節點,檢索到插入位置為第一個鍵值位置,因此要更新其父親節點中對應位置的索引值,這樣root的第一個鍵值就由53變為了49。同時,由于n1中的鍵值個數已經超過了階數M,所以要對這個節點執行分裂操作。

圖4.5?插入數據49及B+樹的分裂

B+樹節點分裂操作:

  • 創建兄弟節點brother,將分裂節點中后半部分鍵值挪動到brother中。
  • 并將brother中首個鍵值插入到父親節點中,將brother節點設為父節點的孩子節點。

⑤?插入145

直接將145插入到節點n2中去,因為插入后鍵值數量未超過B樹的階數,不需要分裂。

圖4.6?向B+樹中插入145

⑥?插入36

將36插入到n1的首個位置處,然后更新器父親節點對應的鍵值。(B+樹中向葉子節點的首個關鍵字位置插入數據,一定會更新父親節點的索引

圖4.7?向B+樹中插入36

⑦?插入101

將101插入到n2的鍵值75和39之間,然后n2分裂。

圖4.8?向B+樹中插入101

4.2 B*樹

相比于B+樹,B*樹要求每個分支節點的鍵值利用率達到\frac{2}{3}M,并且每一層節點又要存儲指向其兄弟節點的指針,B*樹相對于B+樹,最大的優化就是節省了空間,能減少空間浪費。

圖4.9 B*樹的結構

五. B樹索引原理

5.1?索引概述

索引,就是通過某些關鍵信息,讓用戶可以快速找到某些事物,例如通過目錄,我們就可以快速檢索到一本書中特定的內容所在的頁碼。B/B+最普遍的用途,就是做索引

MySQL數據庫官方給出的索引定義是:索引(index)是幫助MySQL高效獲取數據的數據結構。

當數據量很大的時候,為了方便數據的管理、提高檢索效率,通常會將數據保存至數據庫。數據庫不僅僅要存儲數據,還要維護特定的數據結構和一些高效的搜索算法,以幫助用戶快速引用到某些數據。這種實現快速查找的數據結構,就是索引。

MySQL是非常流行的開源關系型數據庫,不僅免費,而且搜索效率較高,可靠性高,擁有靈活的插件式存儲引擎,在MySQL中,索引是屬于存儲引擎范疇的概念,不同的存儲引擎對索引的實現方式是不同的。索引是基于表的而不是基于數據庫的。

5.2 MyISAM

在早期的MySQL數據庫中,所使用的搜索引擎都是MyISAM,這種搜索引擎不支持事務,支持全文索引,其使用的數據結構是B+樹。在MyISAM搜索引擎中,葉子節點中的data域存儲的是數據在磁盤中的地址,而不是數據本身。如圖5.1所示的學生信息管理數據庫,要記錄學生的學號(StuId)、年齡(age)以及姓名,B+樹用于檢索,圖5.1中選取的主鍵為StuId。

在絕大部分數據庫中,一般要求加入到數據庫中的數據要有一個主鍵,并且主鍵是不允許出現重復的。就以圖5.1所示的學生信息管理系統為例,選取學號能保證每個學生之間的學號不重復,而姓名和年齡則不可避免的出現重復,那么就應當選取學號作為主鍵。如果沒有一個合適的參數作為主鍵,那么可以采用自增主鍵,自增主鍵實際就是一個常數,第一次插入的數據常數1為主鍵,第二次插入的數據常數2為主鍵,以此類推。

圖5.1 MyISAM主鍵索引

以圖如果用戶通過主鍵索引查找數據庫中的相關信息,那么就會對B樹進行檢索,直到檢索到葉子節點發現匹配項或者確認數據庫中沒有對應主鍵即可。如果使用非主鍵(未建立輔助索引)的參數進行檢索,那么進行的操作是全表掃描查找匹配項

對于MySQL數據庫,我們處理使用主鍵建立主索引之外,還可以建立輔助索引,主索引不允許出現重復項,而輔助索引允許出現重復項,如圖5.2所示,就是通過學生年齡age建立的學生數據庫的輔助索引。

圖5.2?已age為主鍵的MyISAM輔助索引

5.3 InnoDB

現在高版本的MySQL數據庫,全部采用InnoDB為搜索引擎,InnoDB是面向在線事務處理的應用,支持B+樹索引、哈希索引、全文索引等。但是,InnoDB使用B+樹支持索引的實現方式與MyISAM卻有著很大的不同。

InnoDB文件本身就是索引文件的一部分。在InnoDB的中,B+樹的葉子節點要存放表的全部數據,數據庫中的數據,要按照主鍵從小到大的順序排列起來。如圖5.3所示,InnoDB的葉子節點中要包含所有的數據記錄,這種索引叫做聚集索引。由于InnoDB數據文件本身要按照主鍵來聚集,因此InnoDB必須有主鍵,而MyISAM則可以沒有主鍵

圖5.3 InnoDB主鍵索引

InnoDB建立B+樹輔助索引,葉子節點的數據域中記錄的并不是數據數據文件本身的內容,而是對應的主鍵,如圖5.4所示,在InnoDB索引方式下,建立對于name的輔助索引,葉子結點數據域就存儲了對應的StdId(學號),使用輔助索引檢索時,先拿到對應的主鍵,再通過主索引查找內容,這樣就相當于要檢索兩次

圖5.4 InnoDB輔助索引

六.?總結

  • 常見的搜索結構有哈希、二分、順序查找、平衡二叉樹等,這些數據結構和算法都只適用于內查找。
  • 對于海量數據,內存中無法容納,應當使用B樹/B+樹來進行檢索,B/B+樹是高效的外查找專用數據結構。
  • MySQL數據庫的檢索主要是通過B+樹來進行的,有MyISAM和InnoDB兩種檢索方式,MyISAM的B+樹的葉子節點的數據域中存儲的是數據文件在磁盤中的地址,InnoDB的B+樹的葉子節點中數據域存放的是數據文件本身。
  • B+樹做外查找時,B+樹本身存儲在磁盤中。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/209114.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/209114.shtml
英文地址,請注明出處:http://en.pswp.cn/news/209114.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

博途PLC SCL間接尋址編程應用

這篇博客里我們將要學習Pointer和Any指針&#xff0c;PEEK和POKE指令&#xff0c;當然我們還可以數組類型數據實現數組指針尋址&#xff0c;具體應用介紹請參考下面文章鏈接&#xff1a; https://rxxw-control.blog.csdn.net/article/details/134761364https://rxxw-control.b…

一文講解如何從 Clickhouse 遷移數據至 DolphinDB

ClickHouse 是 Yandex 公司于2016年開源的 OLAP 列式數據庫管理系統&#xff0c;主要用于 WEB 流量分析。憑借面向列式存儲、支持數據壓縮、完備的 DBMS 功能、多核心并行處理的特點&#xff0c;ClickHouse 被廣泛應用于廣告流量、移動分析、網站分析等領域。 DolphinDB 是一款…

【Hadoop_02】Hadoop運行模式

1、Hadoop的scp與rsync命令&#xff08;1&#xff09;本地運行模式&#xff08;2&#xff09;完全分布式搭建【1】利用102將102的文件推到103【2】利用103將102的文件拉到103【3】利用103將102的文件拉到104 &#xff08;3&#xff09;rsync命令&#xff08;4&#xff09;xsync…

使用 HTML 地標角色提高可訪問性

請務必確保所有用戶都可以訪問您的網站&#xff0c;包括使用屏幕閱讀器等輔助技術的用戶。 一種方法是使用 ARIA 地標角色來幫助屏幕閱讀器用戶輕松瀏覽您的網站。使用地標角色還有其他好處&#xff0c;例如改進 HTML 的語義并更輕松地設置網站樣式。在這篇博文中&#xff0c;我…

深度探索Linux操作系統 —— 構建initramfs

系列文章目錄 深度探索Linux操作系統 —— 編譯過程分析 深度探索Linux操作系統 —— 構建工具鏈 深度探索Linux操作系統 —— 構建內核 深度探索Linux操作系統 —— 構建initramfs 文章目錄 系列文章目錄前言一、為什么需要 initramfs二、initramfs原理探討三、構建基本的init…

tomcat篇---第二篇

系列文章目錄 文章目錄 系列文章目錄前言一、tomcat容器是如何創建servlet類實例?用到了什么原理?二、tomcat 如何優化?三、熟悉tomcat的哪些配置?前言 前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到網站,這篇文章男女…

Web應用JSON數據保護(密碼算法、密鑰、數字簽名和數據加密)

1.JSON&#xff08;JavaScript Object Notation&#xff09; JSON是一種輕量級的數據交換格式&#xff0c;采用完全獨立于編程語言的文本格式來存儲和表示數據。JSON通過簡單的key-value鍵值對來描述數據&#xff0c;可以被廣泛用于網絡通信、數據存儲等各種應用場景&#xff0…

【重點】Flink四大基石

1. Time&#xff08;時間機制&#xff09; 時間概念 處理時間&#xff1a;執行具體操作時的機器時間&#xff08;例如 Java的 System.currentTimeMillis()) &#xff09;事件時間&#xff1a;數據本身攜帶的時間&#xff0c;事件產生時的時間。攝入時間&#xff1a;數據進入 …

代碼隨想錄算法訓練營第四十六天 _ 動態規劃_198.打家劫舍、213.打家劫舍II、337.打家劫舍 III。

學習目標&#xff1a; 動態規劃五部曲&#xff1a; ① 確定dp[i]的含義 ② 求遞推公式 ③ dp數組如何初始化 ④ 確定遍歷順序 ⑤ 打印遞歸數組 ---- 調試 引用自代碼隨想錄&#xff01; 60天訓練營打卡計劃&#xff01; 學習內容&#xff1a; 198.打家劫舍 動態規劃五步曲&a…

Python面向對象基礎

Python面向對象基礎 一、概念1.1面向對象的設計思想1.2 面向過程和面向對象1.2.1 面向過程1.2.2 面向對象1.2.3 面向過程和面向對象的優缺點 二、類和對象2.1 概念2.2 類的定義2.3 對象的創建2.3.1 類中未定義構造函數2.3.2 類中定義構造函數 2.4 類的設計 三、類中的成員3.1 變…

vue文件下載

第一種方法 const downloadfile (url) > {if (!url) {return ElMessage.error("暫無文件&#xff01;無法下載")}axios({url,method: GET,responseType: blob// headers: {// token:getCache(TOKEN), // 可以攜帶token// }}).then(res > {const href …

go-zero 開發入門-API服務開發示例

接口定義 定義 API 接口文件 接口文件 add.api 的內容如下&#xff1a; syntax "v1"info (title: "API 接口文件示例"desc: "演示如何編寫 API 接口文件"author: "一見"date: "2023年12月07日"version: "…

Python教程-數組

作為軟件開發者&#xff0c;我們總是努力編寫干凈、簡潔、高效的代碼。在本文中&#xff0c;我們將探索 Python 數組的各種特性和功能。我們將學習如何在 Python 中創建、操作和使用數組&#xff0c;以及數組與 Python 編程語言中的其他數據結構有何不同。我們的目標是提供有關…

找重復的數據(一維數組)

在一大堆數據中找出重復的是一件經常要做的事情。現在&#xff0c;我們要處理許多整數&#xff0c;在這些整數中&#xff0c;可能存在重復的數據。 你要寫一個程序來做這件事情&#xff0c;讀入數據&#xff0c;檢查是否有重復的數據。如果有&#xff0c;輸出“YES”這三個字母…

資源文件、布局管理器、樣式表拓展

QT 資源文件 提供了和本地路徑無關的資源管理。 圖片資源的獲取&#xff1a;阿里巴巴矢量圖庫&#xff08;&#x1f448; 安全鏈接&#xff0c;放心跳轉&#xff09; widget.ui .qrc widget.h #ifndef WIDGET_H #define WIDGET_H#include <QtWidgets>namespace Ui { c…

Plonky2 = Plonk + FRI

Plonky2由Polygon Zero團隊開發&#xff0c;實現了一種快速的遞歸SNARK&#xff0c;據其團隊公開的基準測試&#xff0c;2020年&#xff0c;以太坊第一筆遞歸證明需要60s生成&#xff0c;而于今Plonky2在 MacBook Pro上生成只需 170 毫秒。 下面將逐步剖析Plonky2。 整體構造 …

活久見—當設置不同坐標系統時,ArcMap中的圖形相關位置關系會變化

這兩天一件十分神奇的事情發生了&#xff1a;當設置不同坐標系統時&#xff0c;ArcMap中的圖形相對位置關系會變化。 事情起因是這樣的&#xff1a;博主和同行用ArcMap同時驗證2個相鄰多邊形的相對位置關系&#xff0c;見下圖圖1和圖2的多邊形&#xff0c;在博主的ArcMap中&am…

大電流H橋電機驅動電路的設計與解析(包括自舉電路的講解,以IR2104+LR7843為例)

大電流H橋電機驅動電路的設計與解析&#xff08;包括自舉電路的講解&#xff0c;以IR2104LR7843為例&#xff09; 電機驅動板主要采用兩種驅動芯片&#xff0c;一種是全橋驅動&#xff08;如&#xff1a;HIP4082&#xff09;&#xff0c;一種是半橋驅動&#xff08;如&#xff…

單片機語言--C51語言的數據類型以及存儲類型以及一些基本運算

C51語言 本文主要涉及C51語言的一些基本知識&#xff0c;比如C51語言的數據類型以及存儲類型以及一些基本運算。 文章目錄 C51語言一、 C51與標準C的比較二、 C51語言中的數據類型與存儲類型2.1、C51的擴展數據類型2.2、數據存儲類型 三、 C51的基本運算3.1 算術運算符3.2 邏輯…

奇數位字符反轉算法

題目描述&#xff1a; 題目描述 編寫函數void oddReverse(char *s),將所有奇數位的字符反轉。輸入格式 輸入一個字符串 s保證輸入字符串 s 的長度大于等于1小于等于100輸出格式 輸出修改后的字符串 s。輸入樣例1 012345輸出樣例1 052341輸入樣例2 01234輸出樣例2 03214輸入樣例…