C++學(xué)習(xí)筆記 —— 關(guān)聯(lián)容器map

一宁赤、關(guān)聯(lián)容器

關(guān)聯(lián)容器(associative container)是對(duì)容器概念的另一個(gè)改進(jìn)筹燕。關(guān)聯(lián)容器將值與鍵關(guān)聯(lián)在一起,并使用鍵來查找值蛹含。例如毅厚,值可以是表示雇員信息(如姓名、地址浦箱、電話)的結(jié)構(gòu)吸耿,而鍵可以是唯一的員工編號(hào)。為獲取雇員信息酷窥,程序?qū)⑹褂面I查找雇員結(jié)構(gòu)咽安。對(duì)容器X,表達(dá)式X::key_type指出了鍵的類型蓬推。

關(guān)聯(lián)容器的優(yōu)點(diǎn)在于妆棒,它提供了對(duì)元素的快速訪問。與序列相似沸伏,關(guān)聯(lián)容器也允許插入新元素糕珊,但不能指定元素的插入位置。原因是關(guān)聯(lián)容器通常有用于確定數(shù)據(jù)放置位置的算法毅糟,以便能夠快速檢索信息红选。

二、map

2.1 簡介

map 是一類關(guān)聯(lián)式容器姆另。它的特點(diǎn)是增加和刪除節(jié)點(diǎn)對(duì)迭代器的影響很小喇肋,除了那個(gè)操作節(jié)點(diǎn)坟乾,對(duì)其他的節(jié)點(diǎn)都沒有什么影響。對(duì)于迭代器來說蝶防,可以修改實(shí)值糊渊,而不能修改key。

在map中慧脱,值與鍵的類型不同渺绒,鍵是唯一的,每個(gè)鍵只對(duì)應(yīng)一個(gè)值菱鸥。multimap與map相似宗兼,只是一個(gè)鍵可以與多個(gè)值相關(guān)聯(lián)。

2.2 頭文件

#include <map> (以前的map.h)

2.3 構(gòu)造函數(shù)

map對(duì)象是模板類氮采,需要關(guān)鍵字和存儲(chǔ)對(duì)象兩個(gè)模板參數(shù):
std:map<int, string> personnel;
這樣就定義了一個(gè)用 int 作為索引,并擁有相關(guān)聯(lián)的指向 string 的指針殷绍。

為了使用方便,可以對(duì)模板類進(jìn)行一下類型定義鹊漠,
typedef map<int, CString> UDT_MAP_INT_CSTRING;
UDT_MAP_INT_CSTRING enumMap;

2.4 基本操作函數(shù)

函數(shù) 作用
begin() 返回指向map頭部的迭代器
clear() 刪除所有元素
count() 返回指定元素出現(xiàn)的次數(shù)
empty() 如果map為空則返回true
end() 返回指向map末尾的迭代器
equal_range() 返回特殊條目的迭代器對(duì)
erase() 刪除一個(gè)元素
find() 查找一個(gè)元素
get_allocator() 返回map的配置器
insert() 插入元素
key_comp() 返回比較元素key的函數(shù)
lower_bound() 返回鍵值>=給定元素的第一個(gè)位置
max_size() 返回可以容納的最大元素個(gè)數(shù)
rbegin() 返回一個(gè)指向map尾部的逆向迭代器
rend() 返回一個(gè)指向map頭部的逆向迭代器
size() 返回map中元素的個(gè)數(shù)
swap() 交換兩個(gè)map
upper_bound() 返回鍵值>給定元素的第一個(gè)位置
value_comp() 返回比較元素value的函數(shù)

2.4.1 遍歷元素

2.4.1.1 迭代器遍歷

反相迭代器:

Map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, “student_one”));
mapStudent.insert(pair<int, string>(2, “student_two”));
mapStudent.insert(pair<int, string>(3, “student_three”));

map<int, string>::reverse_iterator iter;
for(iter = mapStudent.rbegin(); iter != mapStudent.rend(); iter++)
{
    cout<<iter->first<<"   "<<iter->second<<endl;
}

2.4.1.2 數(shù)組遍歷

Map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, “student_one”));
mapStudent.insert(pair<int, string>(2, “student_two”));
mapStudent.insert(pair<int, string>(3, “student_three”));

int nSize = mapStudent.size();
for(int nIndex = 1; nIndex <= nSize; nIndex++) 
{
    cout<<mapStudent[nIndex]<<endl;
}

2.4.1.3 基于范圍的for循環(huán)(C++11)

Map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, “student_one”));
mapStudent.insert(pair<int, string>(2, “student_two”));
mapStudent.insert(pair<int, string>(3, “student_three”));

for(auto & iter : mapStudent)
{
     cout<<iter->second<<endl;
}

在這種for循環(huán)中主到,括號(hào)內(nèi)的代碼聲明一個(gè)類型與容器存儲(chǔ)的內(nèi)容相同的變量,然后指出了容器的名稱躯概。接下來登钥,循環(huán)體使用指定的變量依次訪問容器的每個(gè)元素。

2.4.2 插入元素

2.4.2.1 用數(shù)組方式插入數(shù)據(jù)

Map<int, string> mapStudent;
mapStudent[1] =  “one”;
mapStudent[2] =  “two”;

這樣非常直觀娶靡,但存在一個(gè)性能的問題牧牢。插入2時(shí),先在mapStudent中查找主鍵為2的項(xiàng),沒發(fā)現(xiàn)姿锭,然后將一個(gè)新的對(duì)象插入mapStudent塔鳍,鍵是2,值是一個(gè)空字符串呻此,插入完成后轮纫,將字符串賦為"two"; 該方法會(huì)將每個(gè)值都賦為缺省值,然后再賦為顯示的值焚鲜,如果元素是類對(duì)象掌唾,則開銷比較大。我們可以用以下方法來避免開銷:
mapStudent.insert(map<int, string> :: value_type(2, "two"));

2.4.2.2 用insert函數(shù)插入value_type數(shù)據(jù)

#include <map>
#include <string>
#include <iostream>

using namespace std;

Int main()
{
    Map<int, string> mapStudent;
    mapStudent.insert(map<int, string>::value_type (1, “student_one”));
    mapStudent.insert(map<int, string>::value_type (2, “student_two”));
    mapStudent.insert(map<int, string>::value_type (3, “student_three”));

    map<int, string>::iterator  iter;
    for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
    {
        cout<<iter->first<<”   ”<<iter->second<<endl;
    }
}

2.4.2.3 用insert函數(shù)插入pair數(shù)據(jù)

Map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, “student_one”));
mapStudent.insert(pair<int, string>(2, “student_two”));

可用make_pair代替為:

Map<int, string> mapStudent;
mapStudent.insert(make_pair(1, “student_one”));
mapStudent.insert(make_pair(2, “student_two”));

2.4.3 刪除元素

這里要用到erase函數(shù)恃泪,它有三個(gè)重載了的函數(shù)郑兴,下面在例子中詳細(xì)說明它們的用法
首先犀斋,

Map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, “student_one”));
mapStudent.insert(pair<int, string>(2, “student_two”));
mapStudent.insert(pair<int, string>(3, “student_three”));

2.4.3.1 用迭代器刪除

map<int, string>::iterator iter;
iter = mapStudent.find(1);
mapStudent.erase(iter);

2.4.3.2 用關(guān)鍵字刪除

int n = mapStudent.erase(1);  // 如果刪除了會(huì)返回1贝乎,否則返回0

2.4.3.3 用迭代器,成片的刪除

mapStudent.earse(mapStudent.begin(), mapStudent.end());
// 成片刪除要注意的是叽粹,也是STL的特性览效,刪除區(qū)間是一個(gè)前閉后開的集合

相當(dāng)于clear()

2.4.4 查找元素

2.4.4.1 count函數(shù)

用count函數(shù)來判定關(guān)鍵字是否出現(xiàn)却舀,其缺點(diǎn)是無法定位數(shù)據(jù)出現(xiàn)位置,由于map的特性,一對(duì)一的映射關(guān)系锤灿,就決定了count函數(shù)的返回值只有兩個(gè)挽拔,要么是0,要么是1但校,出現(xiàn)的情況螃诅,當(dāng)然是返回1了。

2.4.4.2 find函數(shù)

用find函數(shù)來定位數(shù)據(jù)出現(xiàn)位置状囱,它返回的一個(gè)迭代器术裸,當(dāng)數(shù)據(jù)出現(xiàn)時(shí),它返回?cái)?shù)據(jù)所在位置的迭代器亭枷,如果map中沒有要查找的數(shù)據(jù)袭艺,它返回的迭代器等于end函數(shù)返回的迭代器,程序說明:

map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, “student_one”));
mapStudent.insert(pair<int, string>(2, “student_two”));
mapStudent.insert(pair<int, string>(3, “student_three”));

map<int, string>::iterator iter;
iter = mapStudent.find(1);
if(iter != mapStudent.end())
{
    cout<<"Find, the value is "<<iter->second<<endl;
}
else
{
    cout<<"Do not Find"<<endl;
}

2.4.4.3 lower_bound和upper_bound函數(shù)

成員函數(shù)lower_bound()和upper_bound()將鍵作為參數(shù)叨粘,且工作原理與處理set時(shí)相同猾编。

2.4.4.4 equal_range函數(shù)

成員函數(shù)equal_range函數(shù)用鍵作為參數(shù),且返回兩個(gè)迭代器升敲,它們表示的區(qū)間與該鍵匹配答倡。為返回兩個(gè)值,該方法將它們封裝在一個(gè)pair對(duì)象中驴党,這里pair的兩個(gè)模板參數(shù)都是迭代器苇羡。

map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, “student_one”));
mapStudent.insert(pair<int, string>(2, “student_two”));
mapStudent.insert(pair<int, string>(3, “student_three”));

pair<map<int, string>::iterator, map<int, string>::iterator> range = mapStudent.equal_range(2);
std::map<int, string>::iterator it;
for (it = range.first; it != range.second; ++it)
    cout << (*it).second << endl;

在聲明中可使用C++11自動(dòng)類型推斷功能,簡化代碼如下:

auto range = mapStudent.equal_range(2);
for (auto it = range.first; it != range.second; ++it)
    cout << (*it).second << endl;

三鼻弧、pair

C++標(biāo)準(zhǔn)程序庫中凡是“必須返回兩個(gè)值”的函數(shù)设江, 也都會(huì)利用pair對(duì)象。

pair可以將兩個(gè)值視為一個(gè)單元攘轩。容器類別map和multimap就是使用pairs來管理其健值/實(shí)值(key/value)的成對(duì)元素叉存。

pair被定義為struct,因此可直接存取pair中的個(gè)別值。

兩個(gè)pairs互相比較時(shí)度帮, 第一個(gè)元素正具有較高的優(yōu)先級(jí)歼捏。
例:

namespace std
{ 
  template <class T1, class T2> 
  bool operator< (const pair<T1, T2>&x, const pair<T1, T2>&y)
  { 
    return x.first<y.first || ((y.first<x.first)&&x.second<y.second); 
  } 
}

3.1 pair的應(yīng)用

pair是將2個(gè)數(shù)據(jù)組合成一個(gè)數(shù)據(jù),當(dāng)需要這樣的需求時(shí)就可以使用pair笨篷,如stl中的map就是將key和value放在一起來保存瞳秽。另一個(gè)應(yīng)用是,當(dāng)一個(gè)函數(shù)需要返回2個(gè)數(shù)據(jù)的時(shí)候率翅,可以選擇pair练俐。pair的實(shí)現(xiàn)是一個(gè)結(jié)構(gòu)體,主要的兩個(gè)成員變量是first second 因?yàn)槭鞘褂胹truct不是class冕臭,所以可以直接使用pair的成員變量腺晾。

四燕锥、make_pair

無需寫出型別, 就可以生成一個(gè)pair對(duì)象
例:
std::make_pair(42, '@');
而不必費(fèi)力寫成:
std::pair<int, char>(42, '@')

當(dāng)有必要對(duì)一個(gè)接受pair參數(shù)的函數(shù)傳遞兩個(gè)值時(shí)悯蝉, make_pair()尤其顯得方便归形,

void f(std::pair<int, const char*>);

void foo
{ 
  f(std::make_pair(42, '@')); //pass two values as pair 
}

4.1 make_pair函數(shù)

template pair make_pair(T1 a, T2 b) { return pair(a, b); }

很明顯,我們可以使用pair的構(gòu)造函數(shù)也可以使用make_pair來生成我們需要的pair鼻由。一般make_pair都使用在需要pair做參數(shù)的位置暇榴,可以直接調(diào)用make_pair生成pair對(duì)象很方便,代碼也很清晰蕉世。 另一個(gè)使用的方面就是pair可以接受隱式的類型轉(zhuǎn)換跺撼,這樣可以獲得更高的靈活度。靈活度也帶來了一些問題如:
std::pair<int, float>(1, 1.1);
std::make_pair(1, 1.1);

是不同的讨彼,第一個(gè)就是float歉井,而第2個(gè)會(huì)自己匹配成double。


? 由 Leung 寫于 2018 年 9 月 8 日

? 參考:C++ map的基本操作和使用
    stl map用法和make_pair函數(shù)
    C++ Primer Plus(第6版)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哈误,一起剝皮案震驚了整個(gè)濱河市哩至,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蜜自,老刑警劉巖菩貌,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異重荠,居然都是意外死亡箭阶,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門戈鲁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來仇参,“玉大人,你說我怎么就攤上這事婆殿≌┢梗” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵婆芦,是天一觀的道長怕磨。 經(jīng)常有香客問我,道長消约,這世上最難降的妖魔是什么肠鲫? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮或粮,結(jié)果婚禮上导饲,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好帜消,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著浓体,像睡著了一般泡挺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上命浴,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天娄猫,我揣著相機(jī)與錄音,去河邊找鬼生闲。 笑死媳溺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的碍讯。 我是一名探鬼主播悬蔽,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼捉兴!你這毒婦竟也來了蝎困?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤倍啥,失蹤者是張志新(化名)和其女友劉穎禾乘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體虽缕,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡始藕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了氮趋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伍派。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖剩胁,靈堂內(nèi)的尸體忽然破棺而出拙已,到底是詐尸還是另有隱情,我是刑警寧澤摧冀,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布倍踪,位于F島的核電站,受9級(jí)特大地震影響索昂,放射性物質(zhì)發(fā)生泄漏建车。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一椒惨、第九天 我趴在偏房一處隱蔽的房頂上張望缤至。 院中可真熱鬧,春花似錦康谆、人聲如沸领斥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽月洛。三九已至何恶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嚼黔,已是汗流浹背细层。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留唬涧,地道東北人疫赎。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像碎节,于是被迫代替她去往敵國和親捧搞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容