本人是多年的C碼農(nóng),最近才開始玩C++,所以難免會(huì)遇到C++里很平常普通的東西,在C程序員眼里已經(jīng)灰常神奇了。
舉個(gè)例子,最普通的鏈表,在C里面要構(gòu)建一個(gè)鏈表,要解決的幾個(gè)問(wèn)題:
- 每個(gè)節(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu)
- 節(jié)點(diǎn)的插入、刪除問(wèn)題,以及由此產(chǎn)生的內(nèi)存問(wèn)題
- 鏈表的表頭,表尾問(wèn)題
- 特定節(jié)點(diǎn)的查找,匹配
- 鏈表的遍歷,排序問(wèn)題
- 等等
上面列舉的是鏈表操作的幾個(gè)基本問(wèn)題,但是在C里面要自己構(gòu)建一個(gè)好用且不出錯(cuò)的鏈表,并且把以上基本操作都實(shí)現(xiàn),估計(jì)也得花一番好功夫。
C++就不一樣了,C++提供一個(gè)STL(標(biāo)準(zhǔn)模板類)庫(kù),這個(gè)里面有個(gè)std::map模板類,是一個(gè)關(guān)聯(lián)式容易,簡(jiǎn)單理解為,鏈表里的每個(gè)節(jié)點(diǎn)都是一個(gè)<key, value>對(duì)。
現(xiàn)在就來(lái)看下它是如何減輕碼農(nóng)痛苦的。
一.建一張表
看到這個(gè)問(wèn)題,C碼農(nóng)是不是馬上就要想,哎呀,那我要:
- 先設(shè)計(jì)一個(gè)數(shù)據(jù)節(jié)點(diǎn),并設(shè)計(jì)成鏈表節(jié)點(diǎn);
- 然后再不斷的malloc新節(jié)點(diǎn);
- 再依次把這些節(jié)點(diǎn)串接起來(lái),形成一張表。
把上面這幾點(diǎn)用code實(shí)現(xiàn)并調(diào)通,那就是個(gè)合格的C程序員。
但是我們來(lái)看看用STL提供的模板類有多么方便。
直接上代碼:
sample 1
#include<map>
#include<string>
#include<iostream>
using namespace std;
int main()
{
// 聲明一張表
map<string,int> myMap;
// 依次給這張表添加元素
myMap["a"]=1;
myMap["b"]=2;
myMap["c"]=3;
// 遍歷剛剛建的表
map<string,int>::iterator it;
for(it=myMap.begin(); it!=myMap.end(); ++it)
cout<<"key: "<<it->first <<" value: "<<it->second<<endl;
return 0;
}
這段code輸出為:
key: a value: 1
key: b value: 2
key: c value: 3
哇,是不是有點(diǎn)神奇了,建一張表,以及遍歷這張表,這么簡(jiǎn)單!
怎么看起來(lái)像C的數(shù)組?
其實(shí)不是,其實(shí)是這個(gè)模板類重載了操作符[ ], 讓你看起來(lái)覺得像數(shù)組而已;
這個(gè)有點(diǎn)點(diǎn)誤導(dǎo),我覺得比較純正的還是insert方法,再看下一段code:
sample 2
#include<map>
#include<string>
#include<iostream>
using namespace std;
int main()
{
map<string,int> myMap; // 聲明一張表
// 依次給這張表添加元素
myMap.insert(pair<string, int>("a", 1));
myMap.insert(pair<string, int>("b", 2));
myMap.insert(pair<string, int>("c", 3));
// 遍歷剛剛建的表
map<string,int>::iterator it;
for(it=myMap.begin(); it!=myMap.end(); ++it)
cout<<"key: "<<it->first <<" value: "<<it->second<<endl;
return 0;
}
這次看起來(lái)有點(diǎn)正兒八經(jīng)的鏈表插入的感覺了吧:)
用上C++提供的標(biāo)準(zhǔn)模板庫(kù),有不有點(diǎn)從石器時(shí)代跨入青銅時(shí)代的感覺~~~
二. 刪除節(jié)點(diǎn)
既然有增加節(jié)點(diǎn),那么對(duì)應(yīng)地,就有刪除節(jié)點(diǎn)。
我們先回顧一下C怎么考慮這個(gè)問(wèn)題的:
- 在鏈表中找到特定的節(jié)點(diǎn)。
- 把這個(gè)節(jié)點(diǎn)從鏈表中斷開,把這個(gè)節(jié)點(diǎn)的相鄰節(jié)點(diǎn)鏈上。
- free掉這個(gè)節(jié)點(diǎn)。
裹筋吧,我們看看std:map是怎么讓人happy的。
看代碼:
sample 3
#include<map>
#include<string>
#include<iostream>
using namespace std;
int main()
{
map<string,int> myMap; // 聲明一張表
// 依次給這張表添加元素
myMap.insert(pair<string, int>("a", 1));
myMap.insert(pair<string, int>("b", 2));
myMap.insert(pair<string, int>("c", 3));
// 遍歷剛剛建的表
map<string,int>::iterator it;
for(it=myMap.begin(); it!=myMap.end(); ++it)
cout<<"key: "<<it->first <<" value: "<<it->second<<endl;
cout << endl;
// 刪掉一個(gè)節(jié)點(diǎn)
myMap.erase("b");
map<string,int>::iterator iter;
for(iter=myMap.begin(); iter!=myMap.end(); ++iter)
cout<<"key: "<<iter->first <<" value: "<<iter->second<<endl;
return 0;
}
刪除特定節(jié)點(diǎn)?free廢節(jié)點(diǎn)?自動(dòng)就幫你做了!
三. 清空map
清空操作為什么單獨(dú)拿出來(lái)說(shuō)一下,是因?yàn)槲业谝淮问褂靡卜噶隋e(cuò)誤,因?yàn)樽钊菀紫氲降姆椒ň褪牵罕闅v這個(gè)表,one by one地刪除每一個(gè)節(jié)點(diǎn)。
請(qǐng)看錯(cuò)誤代碼:
map<string,int>::iterator iter;
for(iter=myMap.begin(); iter!=myMap.end(); ++iter) {
myMap.erase(iter);
}
這其實(shí)是錯(cuò)誤的寫法,因?yàn)閑rase會(huì)釋放掉iter,然后執(zhí)行++iter,程序就回跑飛。
所以這里附上一個(gè)推薦的寫法:
map<string,int>::iterator iter;
for(iter=myMap.begin(); iter!=myMap.end(); ) {
// erase() 返回的是下一個(gè)元素的迭代器
iter = myMap.erase(iter);
}
或者再簡(jiǎn)單一點(diǎn):
myMap.clear();
世界清凈了~ 讓我歇會(huì)兒,喝口茶。
四. 幾個(gè)經(jīng)常用的方法
| Item | Description |
|---|---|
| begin() | 返回指向map頭部的迭代器 |
| clear() | 刪除所有元素 |
| empty() | 判斷map是否為空 |
| end() | 返回指向map末尾的迭代器 |
| erase() | 刪除一個(gè)元素 |
| find() | 查找一個(gè)元素 |
| insert() | 插入元素 |
| size() | 返回map中元素的個(gè)數(shù) |
還有其他的就不一一列舉了,還有就是要注意這些方法的重載版本,用的時(shí)候可以特別研究一下。