c++ map是有序还是无序的_C++ STL中Map的按Key排序和按Value排序
map是用來(lái)存放鍵值對(duì)的數(shù)據(jù)結(jié)構(gòu),可以很方便快速的根據(jù)key查到相應(yīng)的value。假如存儲(chǔ)學(xué)生和其成績(jī)(假定不存在重名,當(dāng)然可以對(duì)重名加以區(qū)分),我們用map來(lái)進(jìn)行存儲(chǔ)就是個(gè)不錯(cuò)的選擇。 我們這樣定義,map,其中學(xué)生姓名用string類型,作為Key;該學(xué)生的成績(jī)用int類型,作為value。這樣一來(lái),我們可以根據(jù)學(xué)生姓名快速的查找到他的成績(jī)。
但是,我們除了希望能夠查詢某個(gè)學(xué)生的成績(jī),或許還想看看整體的情況。我們想把所有同學(xué)和他相應(yīng)的成績(jī)都輸出來(lái),并且按照我們想要的順序進(jìn)行輸出:比如按照學(xué)生姓名的順序進(jìn)行輸出,或者按照學(xué)生成績(jī)的高低進(jìn)行輸出。換句話說(shuō),我們希望能夠?qū)ap進(jìn)行按Key排序或按Value排序,然后按序輸出其鍵值對(duì)的內(nèi)容。
一、C++ STL中Map的按Key排序
其實(shí),為了實(shí)現(xiàn)快速查找,map內(nèi)部本身就是按序存儲(chǔ)的(比如紅黑樹(shù))。在我們插入鍵值對(duì)時(shí),就會(huì)按照key的大小順序進(jìn)行存儲(chǔ)。這也是作為key的類型必須能夠進(jìn)行
【參考代碼】
#include
#include
#include
using namespace std;
typedef pair PAIR;
ostream& operator<
return out << p.first << "\t" << p.second;
}
int main() {
map name_score_map;
name_score_map["LiMin"] = 90;
name_score_map["ZiLinMi"] = 79;
name_score_map["BoB"] = 92;
name_score_map.insert(make_pair("Bing",99));
name_score_map.insert(make_pair("Albert",86));
for (map::iterator iter = name_score_map.begin();
iter != name_score_map.end();
++iter) {
cout << *iter << endl;
}
return 0;
}
【運(yùn)行結(jié)果】
大家都知道m(xù)ap是stl里面的一個(gè)模板類,現(xiàn)在我們來(lái)看下map的定義:
template < class Key, class T, class Compare = less,
class Allocator = allocator > > class map;
它有四個(gè)參數(shù),其中我們比較熟悉的有兩個(gè): Key 和 Value。第四個(gè)是 Allocator,用來(lái)定義存儲(chǔ)分配模型的,此處我們不作介紹。
現(xiàn)在我們重點(diǎn)看下第三個(gè)參數(shù):?class Compare = less
這也是一個(gè)class類型的,而且提供了默認(rèn)值 less。 less是stl里面的一個(gè)函數(shù)對(duì)象,那么什么是函數(shù)對(duì)象呢?
所謂的函數(shù)對(duì)象:即調(diào)用操作符的類,其對(duì)象常稱為函數(shù)對(duì)象(function object),它們是行為類似函數(shù)的對(duì)象。表現(xiàn)出一個(gè)函數(shù)的特征,就是通過(guò)“對(duì)象名+(參數(shù)列表)”的方式使用一個(gè) 類,其實(shí)質(zhì)是對(duì)operator()操作符的重載。
現(xiàn)在我們來(lái)看一下less的實(shí)現(xiàn):
template struct less : binary_function {
bool operator() (const T& x, const T& y) const
{return x
};
它是一個(gè)帶模板的struct,里面僅僅對(duì)()運(yùn)算符進(jìn)行了重載,實(shí)現(xiàn)很簡(jiǎn)單,但用起來(lái)很方便,這就是函數(shù)對(duì)象的優(yōu)點(diǎn)所在。stl中還為四則運(yùn)算等常見(jiàn)運(yùn)算定義了這樣的函數(shù)對(duì)象,與less相對(duì)的還有g(shù)reater:
template struct greater : binary_function {
bool operator() (const T& x, const T& y) const
{return x>y;}
};
map這里指定less作為其默認(rèn)比較函數(shù)(對(duì)象),所以我們通常如果不自己指定Compare,map中鍵值對(duì)就會(huì)按照Key的less順序進(jìn)行組織存儲(chǔ),因此我們就看到了上面代碼輸出結(jié)果是按照學(xué)生姓名的字典順序輸出的,即string的less序列。
我們可以在定義map的時(shí)候,指定它的第三個(gè)參數(shù)Compare,比如我們把默認(rèn)的less指定為greater:
【參考代碼】
#include
#include
#include
using namespace std;
typedef pair PAIR;
ostream& operator<
return out << p.first << "\t" << p.second;
}
int main() {
map > name_score_map;
name_score_map["LiMin"] = 90;
name_score_map["ZiLinMi"] = 79;
name_score_map["BoB"] = 92;
name_score_map.insert(make_pair("Bing",99));
name_score_map.insert(make_pair("Albert",86));
for (map::iterator iter = name_score_map.begin();
iter != name_score_map.end();
++iter) {
cout << *iter << endl;
}
return 0;
}
【運(yùn)行結(jié)果】
現(xiàn)在知道如何為map指定Compare類了,如果我們想自己寫(xiě)一個(gè)compare的類,讓map按照我們想要的順序來(lái)存儲(chǔ),比如,按照學(xué)生姓名的長(zhǎng)短排序進(jìn)行存儲(chǔ),那該怎么做呢?
其實(shí)很簡(jiǎn)單,只要我們自己寫(xiě)一個(gè)函數(shù)對(duì)象,實(shí)現(xiàn)想要的邏輯,定義map的時(shí)候把Compare指定為我們自己編寫(xiě)的這個(gè)就ok啦。
struct CmpByKeyLength {
bool operator()(const string& k1, const string& k2) {
return k1.length() < k2.length();
}
};
是不是很簡(jiǎn)單!這里我們不用把它定義為模板,直接指定它的參數(shù)為string類型就可以了。
【參考代碼】
int main() {
map name_score_map;
name_score_map["LiMin"] = 90;
name_score_map["ZiLinMi"] = 79;
name_score_map["BoB"] = 92;
name_score_map.insert(make_pair("Bing",99));
name_score_map.insert(make_pair("Albert",86));
for (map::iterator iter = name_score_map.begin();
iter != name_score_map.end();
++iter) {
cout << *iter << endl;
}
return 0;
}
【運(yùn)行結(jié)果】
二、C++ STL中Map的按Value排序
在第一部分中,我們借助map提供的參數(shù)接口,為它指定相應(yīng)Compare類,就可以實(shí)現(xiàn)對(duì)map按Key排序,是在創(chuàng)建map并不斷的向其中添加元素的過(guò)程中就會(huì)完成排序。
現(xiàn)在我們想要從map中得到學(xué)生按成績(jī)的從低到高的次序輸出,該如何實(shí)現(xiàn)呢?換句話說(shuō),該如何實(shí)現(xiàn)Map的按Value排序呢?
第一反應(yīng)是利用stl中提供的sort算法實(shí)現(xiàn),這個(gè)想法是好的,不幸的是,sort算法有個(gè)限制,利用sort算法只能對(duì)序列容器進(jìn)行排序,就是線性的(如vector,list,deque)。map也是一個(gè)集合容器,它里面存儲(chǔ)的元素是pair,但是它不是線性存儲(chǔ)的(前面提過(guò),像紅黑樹(shù)),所以利用sort不能直接和map結(jié)合進(jìn)行排序。
雖然不能直接用sort對(duì)map進(jìn)行排序,那么我們可不可以迂回一下,把map中的元素放到序列容器(如vector)中,然后再對(duì)這些元素進(jìn)行排序呢?這個(gè)想法看似是可行的。要對(duì)序列容器中的元素進(jìn)行排序,也有個(gè)必要條件:就是容器中的元素必須是可比較的,也就是實(shí)現(xiàn)了
我們知道m(xù)ap中的元素類型為pair,具體定義如下:
template struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair() : first(T1()), second(T2()) {}
pair(const T1& x, const T2& y) : first(x), second(y) {}
template
pair (const pair &p) : first(p.first), second(p.second) { }
}
pair也是一個(gè)模板類,這樣就實(shí)現(xiàn)了良好的通用性。它僅有兩個(gè)數(shù)據(jù)成員first 和 second,即 key 和 value,而且
在?頭文件中,還為pair重載了 < 運(yùn)算符, 具體實(shí)現(xiàn)如下:
template
inline bool
operator& __x, const pair<_t1 _t2>& __y)
{ return __x.first < __y.first
|| (!(__y.first < __x.first) && __x.second < __y.second); }
重點(diǎn)看下其實(shí)現(xiàn):
__x.first < __y.first || (!(__y.first < __x.first) && __x.second < __y.second)
這個(gè)less在兩種情況下返回true,第一種情況:__x.first < __y.first ?這個(gè)好理解,就是比較key,如果__x的key 小于 __y的key 則返回true。
第二種情況有點(diǎn)費(fèi)解: ?!(__y.first < __x.first) && __x.second < __y.second
當(dāng)然由于||運(yùn)算具有短路作用,即當(dāng)前面的條件不滿足是,才進(jìn)行第二種情況的判斷 。第一種情況__x.first < __y.first 不成立,即__x.first >= __y.first 成立,在這個(gè)條件下,我們來(lái)分析下??!(__y.first < __x.first) ?&& __x.second < __y.second
!(__y.first < __x.first) ,看清出,這里是y的key不小于x的key ,結(jié)合前提條件,__x.first < __y.first 不成立,即x的key不小于y的key
即:??!(__y.first < __x.first) ?&& ? !(__x.first < __y.first?) ? 等價(jià)于 ??__x.first == __y.first ,也就是說(shuō),第二種情況是在key相等的情況下,比較兩者的value(second)。
這里比較令人費(fèi)解的地方就是,為什么不直接寫(xiě)?__x.first == __y.first 呢? 這么寫(xiě)看似費(fèi)解,但其實(shí)也不無(wú)道理:前面講過(guò),作為map的key必須實(shí)現(xiàn)
現(xiàn)在我們知道了pair類重載了
而且,既然pair已經(jīng)重載了
typedef pair PAIR;
bool operator< (const PAIR& lhs, const PAIR& rhs) {
return lhs.second < rhs.second;
}
如果pair類本身沒(méi)有重載
那么我們?nèi)绾螌?shí)現(xiàn)對(duì)pair按value進(jìn)行比較呢? 第一種:是最原始的方法,寫(xiě)一個(gè)比較函數(shù); ?第二種:剛才用到了,寫(xiě)一個(gè)函數(shù)對(duì)象。這兩種方式實(shí)現(xiàn)起來(lái)都比較簡(jiǎn)單。
typedef pair PAIR;
bool cmp_by_value(const PAIR& lhs, const PAIR& rhs) {
return lhs.second < rhs.second;
}
struct CmpByValue {
bool operator()(const PAIR& lhs, const PAIR& rhs) {
return lhs.second < rhs.second;
}
};
接下來(lái),我們看下sort算法,是不是也像map一樣,可以讓我們自己指定元素間如何進(jìn)行比較呢?
template
void sort ( RandomAccessIterator first, RandomAccessIterator last );
template
void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );
我們看到,令人興奮的是,sort算法和map一樣,也可以讓我們指定元素間如何進(jìn)行比較,即指定Compare。需要注意的是,map是在定義時(shí)指定的,所以傳參的時(shí)候直接傳入函數(shù)對(duì)象的類名,就像指定key和value時(shí)指定的類型名一樣;sort算法是在調(diào)用時(shí)指定的,需要傳入一個(gè)對(duì)象,當(dāng)然這個(gè)也簡(jiǎn)單,類名()就會(huì)調(diào)用構(gòu)造函數(shù)生成對(duì)象。
這里也可以傳入一個(gè)函數(shù)指針,就是把上面說(shuō)的第一種方法的函數(shù)名傳過(guò)來(lái)。(應(yīng)該是存在函數(shù)指針到函數(shù)對(duì)象的轉(zhuǎn)換,或者兩者調(diào)用形式上是一致的,具體確切原因還不明白,希望知道的朋友給講下,先謝謝了。)
【參考代碼】
int main() {
map name_score_map;
name_score_map["LiMin"] = 90;
name_score_map["ZiLinMi"] = 79;
name_score_map["BoB"] = 92;
name_score_map.insert(make_pair("Bing",99));
name_score_map.insert(make_pair("Albert",86));
//把map中元素轉(zhuǎn)存到vector中
vector name_score_vec(name_score_map.begin(), name_score_map.end());
sort(name_score_vec.begin(), name_score_vec.end(), CmpByValue());
// sort(name_score_vec.begin(), name_score_vec.end(), cmp_by_value);
for (int i = 0; i != name_score_vec.size(); ++i) {
cout << name_score_vec[i] << endl;
}
return 0;
}
【運(yùn)行結(jié)果】
總結(jié)
以上是生活随笔為你收集整理的c++ map是有序还是无序的_C++ STL中Map的按Key排序和按Value排序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: oracle 兰贝斯_【咨询/顾问150
- 下一篇: s3c2440移植MQTT