1.關於set
首先,set是關聯容器,set作為一個容器是用來存儲同一種數據類型的數據結構,基本功能與數組相似。不同的是,在set中每個元素的值都是唯一的。而且系統能夠根據元素的值自動進行排序。但是set中數元素的值並不能直接被改變。
除了set,STL中還有一些標准關聯容器multiset、map和multimap等,這些關聯容器內部均是采用紅黑樹實現的。
set具有以下特性:
(1)map和set的插入刪除效率比其他序列容器高,這是因為:
set中所有元素都是以節點的方式來存儲的,其節點結構和鏈表類似,指向父節點和子節點。所以,在插入和刪除時不需要做內存拷貝和內存移動,故而提高了效率。
(2)每次insert之后,以前保存的iterator不會失效,這是因為:
迭代器iterator在set中就相當於指向節點的指針,只要內存不變,那這個iterator就不會失效。相對於vector來說,每一次的刪除和插入之后,指針都有可能失效,調用push_back在尾部插入的時候情況也是如此。因為為了保證內部數據的連續存放,iterator指向的那塊內存在插入和刪除的過程中可能已經被其他內存覆蓋或者內存已經被釋放掉了。即使是push_back的時候,容器內部空間可能不夠,需要一塊新的更大的內存,只能把以前的內存釋放掉,申請更大的內存,復制已有的數據元素都新的內存中,最后把需要插入的元素放到最后,那么以前的內存指針自然就不可用了。特別是在和find、erase等操作一起使用的時候,一定要注意:不要使用失效的iterator。
vector的內存增長和內存分配原理見:
(3)當數據元素增多時,set的插入和搜索速度變化如何?
如果你知道log2的關系你應該就徹底了解這個答案。在set中查找是使用二分查找,也就是說,如果有16個元素,最多需要比較4次就能找到結果,有32個元素,最多比較5次。那么有10000個呢?最多比較的次數為log10000,最多為14次,如果是20000個元素呢?最多不過15次。看見了吧,當數據量增大一倍的時候,搜索次數只不過多了1次,多了1/14的搜索時間而已。你明白這個道理后,就可以安心往里面放入元素了。
2.set的相關操作
2.1.常用方法
begin() ,返回set容器的第一個元素
end() ,返回set容器的最后一個元素
clear() ,刪除set容器中的所有的元素
empty() ,判斷set容器是否為空
max_size() ,返回set容器可能包含的元素最大個數
size() ,返回當前set容器中的元素個數
rbegin ,返回的值和end()相同
rend() ,返回的值和rbegin()相同
此外,還有一些操作也是set常用的:
(1) count() 用來查找set中某個某個鍵值出現的次數。這個函數在set並不是很實用,因為一個鍵值在set只可能出現0或1次,這樣就變成了判斷某一鍵值是否在set出現過了。
(2)equal_range() ,返回一對定位器,分別表示第一個大於或等於給定關鍵值的元素和 第一個大於給定關鍵值的元素,這個返回值是一個pair類型,如果這一對定位器中哪個返回失敗,就會等於end()的值。
(3)erase(iterator) ,刪除定位器iterator指向的值
erase(first,second),刪除定位器first和second之間的值
erase(key_value),刪除鍵值key_value的值
小結:set中的刪除操作是不進行任何的錯誤檢查的,比如定位器的是否合法等等,所以用的時候自己一定要注意。
(4)find() ,返回給定值值得定位器,如果沒找到則返回end()。
(5)insert(key_value); 將key_value插入到set中 ,返回值是pair<set<int>::iterator,bool>,bool標志着插入是否成功,而iterator代表插入的位置,若key_value已經在set中,則iterator表示的key_value在set中的位置。
inset(first,second);將定位器first到second之間的元素插入到set中,返回值是void.
(6)lower_bound(key_value) ,返回第一個大於等於key_value的定位器
upper_bound(key_value),返回最后一個大於等於key_value的定位器
3.set和multiset、unordered_set的區別
multiset是不去重的,set是去重的;
unordered_set是C++11中引入的新的容器,其內部不再采用紅黑樹實現,而是采用了hash表,加速了檢索速度。
set和map的內部實現是一樣的,unordered_set和unordered_map的內部實現也是一樣的。