C++ 關聯容器
順序容器的底層構造是陣列和連結串列,而關聯容器的底層是紅黑樹、雜湊表,提供高效的查詢、新增和刪除操作。關聯容器與順序容器相比的優勢:
- 具有高效的關鍵字查詢和訪問
- 支援組合(關鍵字+值)的儲存方式
一、關聯容器概述
關聯容器的型別總結如下:
- map,儲存“關鍵字-值”
- set,關鍵字即值,只儲存一個“值”
- multimap,關鍵字可重複的map
- multiset,關鍵字可重複的set
- unordered_map,無序map
- unordered_set,無序set
- unordered_multimap,無序可重複map
- unordered_multiset,無序可重複set
總結一下,主要是map和set兩種,衍生出可重複和無序的各種版本。
各自具有各自的標頭檔案,例如map的標頭檔案< map >
二、map和set
map儲存的是“關鍵字”和“值”的組合體。
map是按關鍵字排序的有序序列,並且關鍵字唯一。
set儲存的“關鍵字”。
set也是按關鍵字排序的有序序列,並且關鍵字唯一。
map主要用於儲存兩個關聯單元,比如儲存圖書名和對應的作者。
set主要用於頻繁查詢,比如在挨個處理單詞時,想把“a”,“the”等詞刪除,那麼就把這些詞放在set中,處理時把每個單詞到set中查一下,如果有,就刪掉。
其餘的版本都是它倆的擴充,可以根據實際需要選擇。
三、map和set的使用
map和set唯一的區別就是map裡放的是繫結的兩個值(關鍵字-值),而set放的單個值,在儲存方面有點類似於順序容器,但是操作比順序容器高效。
- 定義
//map
//未初始化
map<string,int> mp1;
//列表初始化
map<string,int> mp2 = {{"a",1},{"b",2}};
//set
//未初始化
set<string> st1;
//列表初始化
set<string> st2 = {"a","b","c"};
map與set的定義只是型別上的不同,map需要指明兩個型別,set只需一個。
- 訪問
//map
//遍歷訪問
for(auto i = mp2.cbegin(); i != mp2.cend(); i++)
{
cout << i->first << i->second << endl;
//等同於
cout << (*i).first << (*i).second << endl;
}
//按關鍵字訪問
cout << mp2["a"];//輸出的是1
//set
for(auto i = st2.cbegin(); i != st2.cend(); i++)
{
cout << *i << endl;
}
其中遍歷訪問與順序容器類似,因為map儲存的是“關鍵字-值”的型別,所以需要用first訪問關鍵字,用second訪問值。
有意思的是按關鍵字訪問,map按關鍵字升序存放,所以支援以關鍵字為下標的訪問,返回的是關鍵字對應的值。set不支援,因為它就一個值。
set的訪問和順序容器一樣。
- 新增元素
//map
//單個插入
mp2.insert(pair<string,int>("c",2));
//列表插入
mp2.insert({{"d",1},{"e",1}});
//迭代器插入
mp2.inset(b,e);
//set
//單個插入
st2.insert("abc");
//迭代器插入
st2.insert(b,e);
map比較常用的單個插入和列表插入。其中pair是將string和int型別的兩個值繫結在一起。
set的迭代器插入很方便,可以將指向順序容器中的迭代器範圍內的元素插入,前提是型別得相同。
- 查詢
//查詢
auto f = mp2.find("a");
//計數
auto c = count("a");
在map中查詢和計數效果一樣,因為map關鍵字唯一。在multimap中,關鍵字相同的按順序放在一起,所以可以先計數,然後找到第一個,按數量順序訪問。
set類似,它只有一個值。
- 刪除
//按關鍵字刪除
auto e1 = mp2.erase("a");
//按迭代器刪除
auto e2 = mp2.erase(p);
set和map都一樣,都是根據關鍵字或者迭代器刪除,map刪除的是“關鍵字-值”,set刪除的是關鍵字。
四、其他關聯容器
map/set關鍵字唯一,當關鍵字不唯一的時候,可以用mutimap或者mutiset。
map/set自動按升序排序,當順序不重要的時候,可以用unordered_map或者unordered_set。
無序容器不按順序排序,輸出的順序和有序容器可能不同。順序可能不同,但結果是相同的。