C++Primer學習筆記十一——關聯容器、.md
- 關聯容器不支援順序容器的位置相關操作,如 push_back或push_front。原因是關聯容器中元素是按關鍵字儲存的,這些操作對關聯容器沒有意義。
- 關聯容器也不支援建構函式或插入操作這些接受一個元素值和一個數量值的操作
- 關聯容器的迭代器都是雙向的,還有一些關於雜湊效能的操作。
按關鍵字有序儲存元素
map | 關聯陣列;儲存關鍵字-值對 |
---|---|
set | 關鍵字即值 |
multimap | 關鍵字可重複出現的map |
multiset | 關鍵字可重複出現的set |
當定義一個map時,必須既指明關鍵字型別又指明值型別; 無序集合
unordered_map | 用雜湊函式組織的map |
---|---|
unordered_set | 用雜湊函式組織的set |
unordered_multimap | 雜湊組織的map;關鍵字可以重複出現 |
unordered_multiset | 雜湊組織的set;關鍵字可以重複出現 |
//使用map統計單詞數 int main(int argc,char **argv) { map<string,size_t> word_count; fstream in("1.txt"); string word; while(in>>word) ++word_count[word]; for(auto it=word_count.begin();it != word_count.end();it++) { cout<<it->first<<":"; cout<<it->second<<endl; } cout<<endl; return 0; }
關聯容器的初始化與順序容器類似,在此就不必詳細介紹
有序容器在定義其關鍵字時,其關鍵字的型別必須包含元素比較的方法,如果是一個類型別,且沒有包含比較方法,則不合法,可以自行定義比較型別。
當我們使用decltype作用於某個函式時,它返回函式型別而非指標型別,因此我們需要顯示的加上*已表明我們需要返回指標。作用:選擇並返回運算元的型別,若為函式,則型別為函式的返回型別
- 當從map提取元素時,會得到一個pair型別的物件,儲存first和second的資料成員。可以使用列表對關聯容器進行初始化;
- 關聯容器不支援順序容器的位置相關操作,如push_back,push_front,因為關聯容器使用關鍵字儲存。
- 關聯容器的迭代器是雙向的
pair型別 pair的預設建構函式對資料成員進行值初始化
pair<T1,T2> p | p是一個pair,兩個型別分別為T1和T2的成員 |
---|---|
pair<T1,T2> p(v1,v2) | 分別用v1,v2來初始化first,second成員 |
pair<T1,T2> p={v1,v2} | 等價於p(v1,v2) |
make_pair(v1,v2) | 返回一個用v1,v2初始化的pair |
關聯容器的操作
key_type | 此容器型別的關鍵字型別 |
---|---|
mapped_type | 每個關鍵字關聯值的型別,只適用於map |
value_type | 對於set,與key_value相同 對於map,為pair<const key_type,mapped_type> |
- 對於map而言value_type是一個pair型別,其first成員儲存const的關鍵字,second成員儲存值,我們可以改變pair的值,但不能改變pair的關鍵字
- set的迭代器時const的,即使同時定義了iterator和const_iterator型別,但都只能只讀訪問元素
- 通常不對關聯容器使用泛型演算法,關鍵字是const這一特性意味著不能將關聯容器傳遞給修改容器和重排元素的演算法。
新增元素 對於map和set包含不重複的關鍵字,因此插入一個已存在的關鍵字沒有影響
向map新增元素 對一個map容器進行insert操作時,必須記住元素型別是pair,通常需要構造一個pair再進行插入
word_count.insert({word,1});
word_count.insert(make_pair(word,1));
word_count.insert(pair<string,size_t>(word,1));
word_count.insert(map<string,size_t>::value_type(word,1));
c.insert(v) c.emplace(args) | v是value_type型別的物件; args用來構造一個元素 |
---|---|
c.insert(b,e) | b,e是一對迭代器,表示一個c::value_type型別值的範圍 |
c.insert(li) | 插入一個列表 |
c.insert(p,v) | 將迭代器p作為一個指示,指示從哪裡開始搜尋新元素應該儲存的位置 |
檢測insert的返回值 對於不包含重複元素的關聯容器插入時 insert的返回值依賴於容器型別和引數,新增單一元素的insert和emplace返回一個pair,告訴我們插入是否成功,pair的first是一個迭代器,指向具體給定關鍵字的元素,second的成員是一個bool值,指出元素是否已經成功插入到容器中,還是已經存在在容器中。
eg: auto ret = v.insert({word,1}); ret 儲存的是insert的返回值,是一個pair; ret.first 是pair的第一個成員,是一個map迭代器,指向給定關鍵字的元素; ret.first-> 解引用此迭代器,提取map中的元素,元素也是一個pair; ret.first->second map中元素的值部分; ret.second 是一個bool值
當向允許重複元素的容器新增元素時,insert返回值一個指向新元素的迭代器,這裡不會返回一個bool值。
刪除元素
c.erase(k) | 從c中刪除每個關鍵字為k的元素。返回一個size_type值,指出刪除元素的數量 |
---|---|
c.erase§ | 從c中刪除迭代器p指向的元素,p必須指向一個真實元素。返回一個指向p之後元素的迭代器,若p指向c.end(),則返回c.end() |
c.erase(b,e) | 刪除迭代器對b和e所表示的範圍中的元素 |
map的下標操作 c[k] 返回一個關鍵字為k的元素,如果k不在c中的話,新增一個關鍵字為k的元素,對其進行值初始化。 c.at(k) 訪問一個關鍵字為k的元素,帶引數檢查,如果k不存在丟擲out_range_of異常
- 使用一個不在容器中的元素作為下標,會新增一個具有此關鍵字的元素到map中。
- set型別不支援下標操作,因為set中沒有與關鍵字相關聯的值。
- 當對一個map進行下標操作時,會獲得一個mapped_type物件 ;但當解引用一個map迭代器時,會得到一個value_type物件;
訪問元素
下標和at只適用於非const的map和unordered_map
c.find(k) | 返回一個迭代器,指向第一個關鍵字為k的元素,若k不在容器中,則返回一個尾後迭代器 |
---|---|
c.count(k) | 返回關鍵字等於k的數量,對於不允許重複關鍵字的容器,返回值永遠為0或1 |
c.lower_bound(k) | 返回一個迭代器,指向第一個關鍵字不小於k的元素 |
c.upper_bound(k) | 返回一個迭代器,指向第一個大於k的元素 |
c.equal_range(k) | 返回一個迭代器pair,表示關鍵字等於k的元素的範圍,若k不存在,pair的兩個成員都等於end(); |
equal_range返回一個迭代器pair,若關鍵字存在,則第一個迭代器指向第一個與迭代器匹配的元素,第二個迭代器指向最後一個匹配元素之後的位置。
- 如果一個關鍵字不在map中,則lower_bound會返回關鍵字的第一個安全插入點——不影響容器的順序插入位置。
- 如果lower_bound和upper_bound返回相同的容器,則給定關鍵字不在容器中
無序容器
無序容器在儲存組織上為一個桶,每個桶儲存零個或多個元素,無序容器使用一個雜湊函式對映到桶,容器將具有一個特定雜湊值的元素儲存在相同的桶裡。 桶介面 c.bucket_count() 正在使用的桶的數目 c.max_bucket_count() 最多能容納的桶的數目 c.bucket_size(n) 第n個桶有多少個元素 c.bucket(k) 關鍵字為k的元素在哪個桶
桶迭代 local_iterator 可以用來訪問桶中元素的迭代器型別 const_local_count 桶迭代器的const版本 c.begin(n),c.end(n) 桶n的首元素迭代和尾元素迭代
雜湊策略
c.load_factor() 每個桶的平均元素 c.reserve(n) 重組儲存,使得c可以儲存n個元素且不必rehash 無序容器對關鍵字型別的要求 不能直接定義關鍵字型別為自定義類型別的無序容器,需要提供函式來替代==運算子和雜湊計算函式