国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

map和set的使用和原理

2019-11-08 18:53:21
字體:
來源:轉載
供稿:網友

我們學習過順序容器如vecor,list等,它們中的元素是按照在容器中的位置來順序保存和訪問的。而接下來要學習的關聯容器則有根本的不同,它們中的元素是按關鍵字來保存和訪問的。 在《C++PRimer》中列舉了標準庫中的8個關聯容器,如下:

這里寫圖片描述

關聯容器支持高效的關鍵字查找和訪問,我們在這里介紹兩個主要的關聯容器set和map。

map

map里面存的是一些key-value對,其中key起到索引的作用, 而value則表示于索引相關聯的數據。 比如字典就是一個很好使用map的例子,把單詞當作key,解釋當作value。其實map類型也常稱做關聯數組,它和一般的數組類似,可以認為它key就是數組的下標(只不過不必是整數),value則是數組存的值,還是上面的字典例子,比如有某個單詞為right,它的其中一個解釋為右邊的,我們就可以使用類似數組的方式a[“right”]訪問到“右邊的”這個解釋。

set

set里面每個元素只存有一個key,它支持高效的關鍵字查詢操作,比如檢查一個關鍵字是否在set中或者在 某些文本處理過程中可用set保存想要忽略的單詞



在學習這兩種關聯容器之前,我們可以先看一兩個如何使用這類容器的例子。

假設一個字符串數組,里面的每個字符串都是水果,比如蘋果,梨子等,現在要統計每種水果出現的次數。

string fruit[] ={ "apple", "pear", "watermelon", "peach", "banana", "apple", "pear", "watermelon", "peach", "apple", "pear", "watermelon", "apple", "pear", "apple",};size_t n = sizeof(fruit) / sizeof(fruit[0]);map<string, size_t> countFruit;//定義map用來存取每種水果和它的次數for (size_t i = 0; i < n; ++i)//增加每種水果的次數{ ++countFruit[fruit[i]];}for (const auto& element : countFruit)//打印每種水果以及它的次數{ cout << element.first << " : " << element.second << endl;}

對于上面的程序,首先定義了一個map來存取每種水果和它的次數,map也是模板,我們必須指定key和value,在這個程序中,key為string表示水果,value為size_t表示次數。

此時map里面的每個元素都是一個pair類型的對象,簡單來說pair是個模版類型,保存兩個public成員first和second分別對應key和value。

在上面我們說過,可以通過a[key]訪問到value,因此在本例中,我們類似的也用countFruit[fruit[i]]訪問到次數,但是需要注意的一點是,如果當前fruit[i]還不在map中,則創建新元素,且它的key為fruit[i],value為0。不管元素是否是新創建的,我們都將value加1。

最后的打印操作,我們使用了范圍for語句,訪問到map的每個元素(pair類型),然后打印他們的key和value。結果如下圖:

這里寫圖片描述

上一個例子我們進行一個簡單的擴展,比如可能某種水果太貴了比如pear,watermelon等等,我們忽視這些輸入,我們則可以用set保存要想要忽略的單詞,只對不在set集合的單詞統計次數。

map<string, size_t> countFruit;//定義map用來存取每種水果的次數set<string> exclude = {"watermelon", "banana"};for (size_t i = 0; i < n; ++i){ if (exclude.find(fruit[i]) == exclude.end()) ++countFruit[fruit[i]];}

我們定義了一個set用來保存需要忽略的元素,類似的set也是一個模板,我們需要傳入一個key類型。這個程序僅僅是多加了一句if,我們來看看是怎么回事。我們調用它的find函數,它返回一個迭代器,如果給定key在set中,則迭代器指向該key,不然返回尾后迭代器以表示沒找到。這里面我們就完成了僅當每種水果不在忽略集合中再統計它的次數。結果如下圖:

這里寫圖片描述



看完了上面的例子,我們對map和set有了一個大致的了解,下面我們僅對一些常用操作進行介紹,其余的可以參考C++文檔查詢map和set完整詳細用法。

在上面,我們對map和set進行了一個說明,map是以key-value的形式存取,set以key形式存取,他們的底層都是以紅黑樹的結構實現,因此插入刪除等操作都在O(logn)時間內完成,因此可以完成高效的插入刪除。

由于是他們的底層是紅黑樹,因此在插入時候他們會默認執行排序操作,且他們key都是唯一的,因此從這個角度看,他們在某種程度上可以實現過濾重復值排序(默認升序)的功能。

在上面的統計水果次數例子中,對于重復水果,key = “apple”時對關鍵字沒有任何影響,但是可以改變value的值,這樣才實現了統計重復值的次數這一操作。另外注意我們用范圍for對map打印結果依次是

這里寫圖片描述

這是按照字符ascii碼的順序升序得到的,因此有時候也可以讓map/set排序。

但是,如果想要改變默認次序,我們可以對map/set的構造函數傳入一個函數對象進行降序,下面我們來看看它的一些構造函數和拷貝構造函數。

bool fncomp (char lhs, char rhs) {return lhs<rhs;}struct classcomp { bool Operator() (const char& lhs, const char& rhs) const {return lhs<rhs;}};int main (){ map<char, int> first;//默認升序 以key abcd 的順序存儲 first['a'] = 10; first['b'] = 30; first['d'] = 50; first['c'] = 70; //注意:map的下標操作,其行為與vector很不相同:使用一個不在容器中關鍵字作為下標,會添加一個具有此關鍵字的元素到map中。一般使用find函數代替下標操作。 map<char, int> second(first.begin(), first.end()); map<char, int> third(second); map<char, int, classcomp> fourth; // 降序 以key dcba的順序存儲 fourth['a'] = 10; fourth['b'] = 30; fourth['d'] = 50; fourth['c'] = 70; bool(*fn_pt)(char, char) = fncomp; map<char, int, bool(*)(char, char)> fifth(fn_pt); // function pointer as Compare}

了解map構造,我們來看下最常用的insert和find操作, 在之前的統計水果次數題,我們插入元素使用[]操作,現在我們換種做法:

void CountFruitTimes(map<string, size_t>& countFruit, string fruit[], size_t n){ for (size_t i = 0; i < n; ++i) { //auto ret = = countFruit.insert(make_pair(fruit[i], 1)); pair<map<string, size_t>::iterator, bool> ret = countFruit.insert(make_pair(fruit[i], 1)); if (!ret.second) { ret.first->second++; } //countFruit[fruit[i]]++; }}

我們寫了個函數完成統計次數的功能,注意到insert返回的是pair類型,它的first為一個迭代器,second為bool類型,如果bool為true說明插入成功,此時它的key為fruit[i],value為1。如果bool為false說明插入失敗,說明該元素已經存在,但是我們可以通過insert返回值ret得到指向該元素的迭代器。

記得之前我們講過map里面每個元素都是一個pair類型,在上面的例子中第一個為string,第二個是size_t,因此ret.first為迭代器訪問到size_t成員并對次數加1。

這樣就完成了統計次數的操作。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 江阴市| 绍兴县| 修文县| 称多县| 册亨县| 扬州市| 图木舒克市| 红河县| 麻阳| 西宁市| 台东市| 宁河县| 旅游| 沙湾县| 铁力市| 晋州市| 印江| 临漳县| 石屏县| 马公市| 五家渠市| 阳朔县| 苍南县| 邓州市| 达日县| 扶绥县| 海门市| 庆阳市| 广宗县| 扶绥县| 改则县| 罗平县| 绥宁县| 南乐县| 宁阳县| 庆安县| 神木县| 灌云县| 临汾市| 宜君县| 泾源县|