標籤:
近期學習了STL中set的使用,在此寫一點點總結和自己的一些體悟。
set集合容器實現了紅/黑樹狀結構(Red-Black Tree)的平衡二叉檢索樹的的資料結構,在插入元素時,它會自動調整二叉樹的排列,把該元素放到適當的位置,以確保每個子樹根節點的索引值大於左子樹所有節點的索引值,而小於右子樹所有節點的索引值;另外,還得確保根節點的左子樹的高度與有字數的高度相等,這樣,二叉樹的高度最小,從而檢索速度最快。要注意的是,它不會重複插入相同索引值的元素,而採取忽略處理。
平衡二叉檢索樹的檢索使用中序遍曆演算法,檢索效率高於vector、deque、和list的容器。另外,採用中序遍曆演算法可將索引值由小到大遍曆出來,所以,可以理解為平衡二叉檢索樹在插入元素時,就會自動將元素按索引值從小到大的順序排列。
那麼現在有人就要問了,為何set的插入、刪除、檢索效率要比其他序列容器高?
首先我們要瞭解set的儲存方式,set內部採用的是紅/黑樹狀結構(也稱為RB樹),紅/黑樹狀結構是一種非常高效的平衡檢索二叉樹。基於紅/黑樹狀結構,set容器內所有元素都是以節點的方式來儲存,其節點結構和鏈表差不多,指向父節點和子節點。結構圖可能如下:
A
/ \
B C
/ \ / \
D E F G
因此插入的時候只需要稍做變換,把節點的指標指向新的節點就可以了。刪除的時候類似,稍做變換後把指向刪除節點的指標指向其他節點也OK了。這裡的一切操作就是指標換來換去,和記憶體移動沒有關係。
那麼當資料元素增多時,set的插入、刪除和搜尋速度變化如何呢?
如果你知道log2的關係你應該就徹底瞭解這個答案。在set中尋找是使用二分尋找,也就是說,如果有16個元素,最多需要比較4次就能找到結果,有32個元素,最多比較5次。那麼有10000個呢?最多比較的次數為log10000,最多為14次,如果是20000個元素呢?最多不過15次。看見了吧,當資料量增大一倍的時候,搜尋次數只不過多了1次,多了1/14的搜尋時間而已。你明白這個道理後,就可以安心往裡面放入元素了。
使用set前,需要在程式標頭檔中包含聲明“#include<set>”。
下面我們列出一些set中的常用操作:(英語好的小夥伴可以進這個連結看看,包含了set的幾乎所有操作)
首先是建立set集合對象:
1 #include<set>2 3 using namespace std;4 5 int main(){6 set<int> s;//定義元素類型為int的集合對象,當前沒有任何元素 7 return 0;8 }
元素的插入與中序遍曆:
採用inset()方法把元素插入到集合中,插入規則在預設的比較規則下,是按元素值從小到大插入,如果自己指定了比較規則函數,則按自訂比較規則函數插入。使用前向迭代器對集合中序遍曆,結果正好是元素排序後的結果。
1 #include<iostream> 2 #include<set> 3 using namespace std; 4 5 int main(){ 6 set<int> s; 7 s.insert(8);//插入了五個元素,但由於第二次插入8有重複,所以第二次插入8並沒有執行 8 s.insert(1); 9 s.insert(12);10 s.insert(6);11 s.insert(8);12 13 set<int>::iterator it;//定義前向迭代器 14 for(it=s.begin();it!=s.end();it++){ //中序遍曆集合中的所有元素 15 cout<<*it<<" ";16 }17 cout<<endl;18 return 0;19 }
運行結果:
1 6 8 12
我們也可以使用反向迭代器reverse_iterator來反向遍曆集合,輸出結果正好是集合元素的反向排序結果。它需要用到rbegin()和rend()兩個方法,他們分別給出了反向遍曆的開始位置和結束位置。
1 #include<iostream> 2 #include<set> 3 using namespace std; 4 5 int main(){ 6 set<int> s; 7 s.insert(8);//插入了五個元素,但由於第二次插入8有重複,所以第二次插入8並沒有執行 8 s.insert(1); 9 s.insert(12);10 s.insert(6);11 s.insert(8);12 13 set<int>::reverse_iterator it;//定義反向迭代器 14 for(it=s.rbegin();it!=rend();it++){//反向遍曆 15 cout<<*it<<" ";16 }17 cout<<endl;18 return 0;19 }
運行結果
12 8 6 1
元素的刪除:
元素可以使用erase()來刪除某索引值的元素,也可以使用clear()來清空集合。
明天更,哈哈
set集合容器