[數據結構]Map和Set

說起map和set,想必我們都學過紅黑樹了吧,map和set就是紅黑樹的一個應用領域。它的底層就是由紅黑樹來實現的。下面簡單說一下map和set的使用吧。

首先,有一個栗子是這樣的,讓我們統計出每種水果出現的次數。

我們會想到怎么解決的。關于map,我們知道,當你插入同樣的key值時,它就不會將要插入的key值插入到map中。但是,我們還知道,map是有倆個參數的,一個是插入的key值,另一個value可以用來統計key值出現的次數。

關于統計水果次數的問題,我們主要有以下幾種方法:

    map<string,int> countMap;string strs[] = {"蘋果","香蕉","橘子","蘋果","蘋果","香蕉"};//1.從頭到尾遍歷看是否有數組中的值,沒有則插入,有則使second++for(int i = 0; i < sizeof(strs)/sizeof(strs[0]); i++){map<string,int>::iterator it = countMap.find(strs[i]);if(it != countMap.end()){it->second++;}else{countMap.insert(make_pair(strs[i],1));}}map<string,int>::iterator it1 = countMap.begin();while(it1 != countMap.end()){cout<<it1->first<<":"<<it1->second<<endl;++it1;}
//2.檢測插入的返回值pair<map<string,int>::iterator,bool>的second是否為false來確定pair<map<string,int>::iterator,bool> ret;for(int i = 0; i < sizeof(strs)/sizeof(strs[0]);i++){ret = countMap.insert(make_pair(strs[i],1));if(ret.second == false)ret.first->second++;}map<string,int>::iterator it1 = countMap.begin();while(it1 != countMap.end()){cout<<it1->first<<":"<<it1->second<<endl;++it1;}
//3.直接使用map重載的[]for(int i = 0; i < sizeof(strs)/sizeof(strs[0]);i++){countMap[strs[i]]++;}map<string,int>::iterator it1 = countMap.begin();while(it1 != countMap.end()){cout<<it1->first<<":"<<it1->second<<endl;++it1;}

運行結果:

這里寫圖片描述

這里需要注意的幾點是:

1.首先使用插入的時候,是需要插入一個pair結構體,因為map底層的value是一個pair結構體,里邊成員又有first和second;因此需要使用make_pair來構造insert的參數。
2.在使用第三種方法的時候,我們使用到map重載的operator[],說一下operator[]的函數:
(*((this->insert(make_pair(x,T()))).first)).second
分解一下上邊的operator[]的式子:
this->insert(make_pair(x,T())):返回值為pair<iterator,bool>結構體
((this->insert(make_pair(x,T()))).first):表示pair結構體中的first,即指向一個pair結構體的迭代器,此pair結構體中有key和value,也即所謂的first和second
(*((this->insert(make_pair(x,T()))).first)).second:表示取迭代器中指向的pair的second

說到map,我們還有一個multimap,是用來插入冗余的值,比如有相同的key值的時候,對于map而言,它就不會將其插入,而對于multimap而言就會插入。典型的例子為字典,我們英譯漢的時候,同一個英語單詞代表著不同的意思,這時multimap就會將每一個key值對應的不同的value值都會插入,并且以排好序的方式顯示。

1.比如map來顯示字典的時候:

typedef map<string,string> Dict;typedef map<string,string>::iterator DictIt;Dict dict;dict.insert(make_pair("left","左邊"));dict.insert(make_pair("right","右邊"));dict.insert(make_pair("left","剩余"));DictIt it = dict.begin();while (it != dict.end()){cout<<it->first<<":"<<it->second<<endl;++it;}

結果為:

這里寫圖片描述

2.用multimap來實現字典的時候:

typedef multimap<string,string> Dict;typedef multimap<string,string>::iterator DictIt;Dict dict;dict.insert(make_pair("left","左邊"));dict.insert(make_pair("right","右邊"));dict.insert(make_pair("left","剩余"));DictIt it = dict.begin();while (it != dict.end()){cout<<it->first<<":"<<it->second<<endl;++it;}

運行結果:

這里寫圖片描述

綜上所述,
(1)map和multimap可以通過key來找value,也可通過key排序
(2)當我們查找某個key值的時候,發現有多個相同的key值,此時不知道it該指向哪個pair結構體,這里要說明的是,它將返回中序遍歷的第一個key值

驗證一下:

typedef multimap<string,string> Dict;typedef multimap<string,string>::iterator DictIt;Dict dict;dict.insert(make_pair("left","左邊"));dict.insert(make_pair("right","右邊"));dict.insert(make_pair("left","剩余"));DictIt it = dict.begin();it = dict.find("left");dict.erase(it);it = dict.begin();while (it != dict.end()){cout<<it->first<<":"<<it->second<<endl;++it;}

在這里,我們找到一個key值為left的pair,此時刪除它后再打印一下發現得出的是比它大的value值。

這里寫圖片描述

說完map和multimap后,與之對應的還有set和multiset。set和multiset是用來判斷這個值存在或者不存在。其次也可以用來排序。還有一個特點是過濾(去重)。

1.檢測其存在或者不存在

void TestSet()
{typedef set<string> MySet;typedef set<string>::iterator MySetIt;MySet myset;string strs[] = {"蘋果","香蕉","橘子","西瓜","草莓","櫻桃"};for(int i = 0; i < sizeof(strs)/sizeof(strs[0]); i++){myset.insert(strs[i]);}MySetIt it = myset.begin();if(it == myset.find("哈密瓜"))cout<<"哈密瓜存在"<<endl;elsecout<<"哈密瓜不存在"<<endl;cout<<"存在的其他水果為:"<<endl;it = myset.begin();while(it != myset.end()){cout<<*it<<endl;++it;}
}

運行結果:

這里寫圖片描述

2.排序和去重

typedef set<int> MySet;typedef set<int>::iterator MySetIt;MySet myset;for(int i = 10; i > 0; i--)myset.insert(i);myset.insert(5);MySetIt it = myset.begin();while(it != myset.end()){cout<<*it<<endl;++it;}

運行結果:

這里寫圖片描述

對于過濾來說,就是如果有相同的key值,它就會去掉相同的key,只插入一個到set中。

這里multiset的意義和multimap差不多,也是處理冗余的數據。使用方法類似。

對于map和set的底層是怎么實現的呢。它是通過寫的一個紅黑樹。主要的區別是

里邊的value_type的意義,對于map來說,value_type指的是一個pair的結構體,結構體成員為key和value,而對于set來說,value_type指的是key值。
在紅黑樹中,用了枚舉來表示顏色。而在源碼的紅黑樹中使用了bool值來代替紅黑倆種顏色
我們還知道,map和multimap,set和multiset也有區別,底層是怎么用紅黑樹的呢。它是插入的時候分別對紅黑樹的插入分為唯一插入(insert_unique)和相等插入(insert_equal)(相等插入就是對冗余數據的考慮)。
set的插入:

map中value_type: typedef pair<const Key, T> value_type;
set中value_type: typedef Key value_type;

set的插入:

  typedef  pair<iterator, bool> pair_iterator_bool; pair<iterator,bool> insert(const value_type& x) { pair<typename rep_type::iterator, bool> p = t.insert_unique(x); return pair<iterator, bool>(p.first, p.second);}

map的插入:

pair<iterator,bool> insert(const value_type& x) 
{ return t.insert_unique(x); }

multimap的插入:

  iterator insert(const value_type& x) { return t.insert_equal(x); }

multiset的插入:

  iterator insert(const value_type& x) { return t.insert_equal(x);}

還可以進行相關的區間的插入,刪除,某個位置的插入刪除等操作。

小姿勢:

lower_bound : 用來找到比key值大的數
upper_bound : 用來找到比key值大的數

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/382712.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/382712.shtml
英文地址,請注明出處:http://en.pswp.cn/news/382712.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

js獲取Json對象的長度

有兩種Json形式&#xff1a; 第一種&#xff1a; var json1 {"data":[{"name":"zs","age":"10"}]};對于這種格式的json數據&#xff0c;如果想獲取data的長度&#xff0c;就可以用以下這種方式&#xff1a; var length …

生產者消費者模型(條件變量)

三種關系&#xff1a;互斥&#xff0c;同步&#xff0c;互斥和同步 兩類角色:生產者&#xff0c;消費者&#xff08;線程&#xff09; 一個交易場所&#xff1a;生產者消費者共享的區域 賣蘋果的模型 dish上面只有一個蘋果買家必須要等賣家把蘋果放到dish上才可以去買蘋果。…

linux之信號

信號&#xff1a;在生活中&#xff0c;我們遇到過不同種類的信號&#xff0c;比如&#xff1a;&#xff08;交通信號&#xff0c;乃至某個人的表情&#xff0c;動作等帶給你不同的信號&#xff09;然而&#xff0c;在我們的linux下&#xff0c;我們最熟悉的就是&#xff0c;當遇…

視頻解析有感,在解析 iqiyi與qq視頻的時候,記錄一些發現

最近對iqiyi與qq視頻解析發現&#xff0c;兩個網站的解析流程&#xff0c;尤其是反解析措施 各有特點&#xff0c;簡單記錄一下 先說iqiyi&#xff0c; 瀏覽器模擬移動端可以拿到視頻的mp4鏈接&#xff0c;這個不多說。 iqiyiPC端瀏覽器獲取 ts過程&#xff1a; a.iqiyi一次性…

C語言atoi函數的用法

#include < stdlib.h > int atoi(const char *nptr);用法&#xff1a;將字符串里的數字字符轉化為整形數。返回整形值。 注意&#xff1a;轉化時跳過前面的空格字符&#xff0c;直到遇上數字或正負符號才開始做轉換&#xff0c;而再遇到非數字或字符串結束時(’/0’)才…

[Linux]繼續探究mysleep函數(競態條件)

之前我們探究過mysleep的簡單用法&#xff0c;我們實現的代碼是這樣的&#xff1a; #include<stdio.h> #include<signal.h>void myhandler(int sig) {}unsigned int mysleep(unsigned int timeout) {struct sigaction act,oact;act.sa_handler myhandler;sigempt…

C語言的atoi和C++的to_string

to_stringint to string將其他型轉換成字符串型atoiascii to integer是把字符串轉換成整型數的一個函數 to_string #include <iostream> // std::cout #include <string> // std::string, std::to_stringint main () {std::string perfect std::to_string…

ubuntu 升級python3.5到python3.7,并升級pip3

1, 下載python3.7.tgz 文件&#xff0c;解壓&#xff0c; 2. 編譯安裝 3. 刪除 /usr/bin 目錄下的 pip3, python3 4. 建立新的軟連接&#xff1a; #添加python3的軟鏈接ln -s /usr/local/python3/bin/python3.7 /usr/bin/python3#添加 pip3 的軟鏈接ln -s /usr/local/python3/b…

[Linux]死鎖

死鎖是指多個進程在運行過程中因爭奪資源而造成的一種僵局&#xff0c;當進程處于這種僵持狀態時&#xff0c;若無外力作用&#xff0c;它們都將無法再向前推進。之前信號量的時候我們知道&#xff0c;如果多個進程等待&#xff0c;主要體現在占有鎖的問題上。死鎖也可以被定義…

Python安裝第三方模塊總結 轉載的

轉自 https://www.jellythink.com/archives/541

[C++]vector創建二維數組

c.resize(n);將c重置為大小為n個元素向量&#xff0c;如果n比原來的元素多&#xff0c;則多出的元素常被初始化為0//節選《面向對象的程序設計》杜茂青 int N5, M6; vector<vector<int> > Matrix(N); for(int i 0; i< Matrix.size(); i){ Matrix[i].resize(M…

[Linux]線程安全和可重入函數

線程安全&#xff1a;一個函數被稱為線程安全的&#xff0c;當且僅當被多個并發進程反復調用時&#xff0c;它會一直產生正確的結果。如果一個函數不是線程安全的&#xff0c;我們就說它是線程不安全的。 重入&#xff1a;函數被不同的控制流程調用,有可能在第一次調用還沒返回…

[Linux]信號量

信號量是一個計數器&#xff0c;用于為多個進程提供對共享數據對象的訪問。 在信號量上只有三種操作可以進行&#xff0c;初始化、遞增和增加&#xff0c;這三種操作都是原子操作。遞減操作可以用于阻塞一個進程&#xff0c;增加操作用于解除阻塞一個進程。 為了獲得共享資源…

Linux VIM 程序中有游離的‘\357’ ‘\274’錯誤

gcc date.cpp -o date -lstdc date.cpp:18:20: 錯誤&#xff1a;程序中有游離的‘\357’date.Showdata()&#xfffd;&#xfffd;&#xfffd;^ date.cpp:18:21: 錯誤&#xff1a;程序中有游離的‘\274’date.Showdata()&#xfffd;&#xfffd;&#xfffd;^ date.cpp:18:22…

[Linux]關于SIGCHLD

之前我們就學過&#xff0c;關于wait和waitpid來處理僵尸進程&#xff0c;父進程等待子進程結束后自己才退出&#xff0c;這樣的方法有倆種方式&#xff0c;一種是父進程死死的等子進程退出&#xff0c;也就是使用阻塞的方式等待子進程退出&#xff0c;另一種方式是通過非阻塞的…

C語言思維導圖

本人能力有限&#xff0c;知識點難免概括不全&#xff0c;如有錯誤歡迎指正

轉載一篇關于curl的文章

轉載一篇關于curl的文章 http://www.360doc.com/content/16/0107/15/18578054_526158476.shtml

[Linux]vi/vim下添加多行注釋和取消注釋

添加注釋&#xff08;Centos&#xff09;&#xff1a; 在命令行模式下按ctrlV進入 visual block模式&#xff08;可視化模式&#xff09; 選中你需要注釋的行&#xff0c;再按大寫的I&#xff0c;輸入//&#xff0c;最后按倆下esc即可。 如果想讓前進tab個位&#xff0c;則可在…

pthread和互斥量條件變量函數意義速查表

數據類型 pthread_t 線程 互斥量和條件變量

[Linux]共享內存

共享內存是UNIX提供的進程間通信手段中速度最快的一種&#xff0c;也是最快的IPC形式。為什么是最快的呢&#xff0c;因為數據不需要在客戶進程和服務器進程之間復制&#xff0c;所以是最快的一種IPC。這是虛存中由多個進程共享的一個公共內存塊。 兩個不同進程A、B共享內存的…