三、【C++ STL】容器之關聯式容器

1、關聯式容器

  關聯容器在存儲時是以關鍵字key爲下標進行存儲的,標準的STL關聯容器分爲set和map兩大類,以後的衍生版本有multiset和multimap,它們的區別是在存儲時是否允許出現關鍵字key相同的狀況。這些容器的底層機制均以RB-tree(紅黑樹)完成。ios

  此外,SGI STL還提供了一個不在標準規格之列的關聯式容器:hash table,以及基於hash table而完成的hash_set和hash_map。但在C++11中,由於標準化的推動,unordered_map原來屬於boost分支和std::tr1中,而hash_map屬於非標準容器。儘可能使用unordered_,代替hash_,兩者在底層上實現機理是同樣的。數據結構

一、對組pair類型提供的操做

對組pair包含兩個數據值。具體的使用方法以下:函數

 

1     pair<T1, T2> p1;

 

建立一個空的pair對象,它的兩個元素分別是T1和T2類型,採用值初始化。性能

 

 

1     pair<T1, T2> p1(v1, v2);

 

建立一個pair對象,它的兩個元素分別是T1和T2類型,其中first成員初始化爲v1,second成員初始化爲v2。學習

 

 

1     make_pair(v1, v2);

 

以v1和v2值建立一個新的pair對象,其元素的類型分別是v1和v2的類型。spa

 

 

1   p1 < p2;

 

兩個pair對象之間的小於運算,其定義遵循字典次序:若是p1.first<p2.first或者!(p2.first<p1.first)&&p1.second<p2.second,返回true。.net

 

 

1   p1 == p2;

 

若是兩個pair對象的first成員和second成員依次相等,則這兩個對象相等,該運算使用其元素的==操做符。設計

 

 

1   p.first、p.second;

 

返回p中名爲first、second的公有數據成員。code

 

二、pair的建立和初始化

  在建立pair對象時,必須提供兩個類型名,pair對象的兩個數據成員各自對應一個,這兩個類型名能夠不一樣。若是在建立pair對象時不提供顯示初始化,則調用默認構造函數對其成員進行初始化;也能夠在建立對象時使用( )直接顯示初始化式:
對象

1     pair<類型1, 類型2> 對象名;

 

若是使用多個相同的pair對象,也可使用typedef簡化其聲明:

1   typedef  pair <string, string>  Author;
2   Author 對象名(初始值1,初始值2);

 

對於pair類能夠直接訪問其數據成員,其成員都是公有的,分別命名爲first成員和second成員,使用點操做符便可訪問。

三、set和map

  通常來講,關聯式容器的內部結構是一個平衡二叉樹,以便得到良好的搜尋效率,平衡二叉樹有不少種類型,包括AVL-tree,RB-tree等,最被普遍使用的是RB-tree。

  (1)   搜索二叉樹,由於它的查找平均性能是O(lgN),所以查詢中多用這種結構,但若是創建搜索二叉樹的時候數據不夠隨機,可能會致使這棵二叉樹出現「左重右輕「之類的失衡狀況,這個時候平衡二叉樹便體現出它的做用了。

  (2)   所謂的樹形平衡與否,並無一個絕對的測量標準,大體意義是沒有任何一個節點過深。AVL樹中定義是任何節點的左右子樹高度相差最多爲1,在插入新的元素的時候,可能會致使這棵AVL樹失去平衡,這個時候就須要用到」單旋轉」和「雙旋轉」兩種操做來調節AVL樹使之從新平衡。

  (3)   RB-tree是另外一種二叉平衡樹,它對「平衡」的定義更弱,它的規則以下:

  A. 每一個節點不是紅色就是黑色

  B. 根節點爲黑色

  C. 若是節點爲紅色,那麼它的子節點必須爲黑色

  D. 任一節點至NULL的任何路徑中,所含的黑色節點數必須相同

  因此對於RB-tree的插入和刪除是一個很複雜的過程,其中,插入有3中狀況,刪除有4中狀況,可是它能很好地保證查詢的效率,一般來講,比其餘的平衡二叉樹提升25%。

  在RB-tree中,有兩個函數很重要,一個是pair<iterator,bool>insert_unique(const Value_type &x),這個是將x插入到紅黑樹中,而且保持節點的獨一無二(一般來講,若是使用insert函數在map插入新的元素,若是是重複元素,則不會真正插入,而是直接返回),返回值是一個pair類型,bool標誌插入是否成功,iterator根據插入是否成功則指向新插入的節點或者NULL,另一個是pair<iterator,bool> insert_equal(constValue_type &x),這個函數再插入節點時容許節點關鍵字key重複,這即是multiset和multimap實現的關鍵了,這也是它們和set及map最大的區別了。

四、hash_set和hash_map

  二叉搜索樹具備對數平均時間的表現,但這樣的表構建在一個假設之:輸入數據足夠隨機。除此以外,還有另一種數據結構,它在插入、刪除、搜尋等操做上也具備常數平均時間,並且這種表現是以統計爲基礎,不須要依賴元素的隨機性,它就是hash table。

  哈希表在處理衝突時有線性探測,二次探測以及開鏈等方式,SGI則是採用開鏈的方式,即將衝突的元素構成一個鏈表,在SGI提供的hashtable中表格內的元素爲桶子(bucket),它是用vector來承載元素。

  雖然在開鏈法中並不要求表格大小必須爲質數,可是SGI STL仍然以質數來設計表格,它是將預先選取的28個質數保存在表中,當用戶要求分配多少個桶時,則返回不小於且最接近的一個質數做爲表格大小。

       Hash_set和hash_map一樣只須要調用hashtable中的函數便可。因爲如今常用unordered_系列代替了hash_,因此對於hash_的具體用法就不贅述了。

2、set

一、set/multiset

  (1)全部元素都會根據元素的鍵值自動排列,set的鍵值就是實值,而且set不容許兩個元素相同的鍵值。

  (2)不能經過set的迭代器改變set的元素值,由於set的元素值就是鍵值,所以這關係到排列規則,若是咱們擅自修改元素值,會破壞set內部的排列規則。也正由於這樣,STL的set的迭代器是const_iterator。

  (3)STL集合的底層結構是紅黑樹。所以掌握了紅黑樹的基本操做,那麼學習集合set將會很容易,幾乎set的全部操做都是轉調用紅黑樹的操做而已。

  (4)set內的相同數值的元素只能出現一次,multiset內可包含多個數值相同的元素。

【示例】

 1 #include <iostream>
 2 #include <set>//用set和multiset前,必須包含頭文件<set>
 3 
 4 using namespace std;
 5 
 6 int main()
 7 {
 8     //type of the collection
 9     typedef set<int> IntSet;
10 
11     IntSet coll;//set container for int values
12     //不可以用push_back()由於是自動排序
13     coll.insert(1);
14     coll.insert(6);
15     coll.insert(2);
16 
17     IntSet::const_iterator pos;
18     for(pos = coll.begin(); pos != coll.end(); pos++)
19         cout << *pos << "  ";
20     cout << endl;
21 
22     return 0;
23 }

二、map/multimap

  (1)map的元素是成對的鍵值/實值,內部的元素依據其值自動排序;

  (2)map內的相同數值的元素只能出現一次,multimap內可包含多個數值相同的元素。

  (3)STL集合的底層結構是紅黑樹。所以掌握了紅黑樹的基本操做,那麼學習集合set將會很容易,幾乎set的全部操做都是轉調用紅黑樹的操做而已。

【示例】

 1 #include <iostream>
 2 //用map/multimap前,必須包含頭文件<map>
 3 #include <map>
 4 #include <string>
 5 
 6 using namespace std;
 7 
 8 int main()
 9 {
10     //type of the collection
11     typedef multimap<int, string> intStringMMap;
12 
13     intStringMMap coll;//container for int/string
14     //make_pair()便捷函數,返回一個pair對象:pir(first, second)
15     coll.insert(make_pair(6, "strings"));
16     coll.insert(make_pair(1, "is"));
17     coll.insert(make_pair(3, "multimap"));
18 
19     intStringMMap::iterator pos;
20     for(pos = coll.begin(); pos != coll.end(); pos++)
21     {
22         cout << pos->first << " " << pos->second << endl;;
23     }
24     cout << endl;
25 
26     return 0;
27 }
相關文章
相關標籤/搜索