1. 程式人生 > >C++ STL: map的按key和按value排序

C++ STL: map的按key和按value排序

本文目錄

1. map定義

在將map的排序之前,我們要知道它是STL裡的一個模板類,用來存放<key, value>鍵值對的資料結構,定義如下。

template < class Key,                                   //map::key_tpe
           class T,                                     //map::mapped_type
           class Compare = less<Key>,                   //map::key_compare
class Alloc = allocator<pair<const Key, T>> //map::allocator_type > class map;
  • 第1個引數儲存了key。

  • 第2個引數儲存了mapped value。

  • 第3個引數是比較函式的函式物件。map用它來判斷兩個key的大小,並返回bool型別的結果。利用這個函式,map可以確定元素在容器中遵循的順序以及兩個元素鍵是否相等(!comp(a,b)&&!comp(b,a)),確保map中沒有兩個元素可以具有等效鍵。這裡,它的預設值是less<Key>,定義如下。

    template <class T> 
    struct less {
      bool operator() (const T& x, const T& y) const {return x < y;}
      typedef T first_argument_type;
      typedef T second_argument_type;
      typedef bool result_type;
    };
    
  • 第4個引數是用來定義儲存分配模型的。

2. 按key排序

實際上map內部所有的資料本來就是按key排序的。分析map結構定義,發現map的按key排序是通過第3個引數(比較函式的函式物件)實現的。

其中,less為其預設的函式物件,所以如果我們不指定引數3,map鍵值對就會按照預設方法進行儲存。當我們希望它能以不同的方式進行排序,就需要重新指定引數3。

如果只是呼叫C++標準庫自帶的方法,我們只需如下所示,在宣告map物件時指定第3引數即可。

#include <iostream>
#include <map>
#include <string>
using namespace std;

int main(){
	map<string, int, greater<string>> test; //指定引數3為greater<string>
	test["Alice"] = 3;
	test["Cindy"] = 11;
	test["Bob"] = 7;

	for(auto itr = test.begin(); itr != test.end(); ++itr){
		cout << itr->first << ": " << itr->second << endl;
	}
	return 0;
}

然而,當我們自定義map的鍵值型別時,C++標準庫往往沒有對應的函式物件可供使用,這時候,我們就需要自定義函式物件了。關於方法,我在C++ STL: map自定義鍵值型別這篇文章裡講得非常詳細,文中提出了針對自定義鍵值排序的4種方法。

3. 按value排序

對value的排序,我查了很多資料,發現大家都是通過將map轉換到vector,再用STL提供的sort方法得以實現的。你們以為我這裡會有什麼新方法麼?抱歉,沒有,(;´༎ຶД༎ຶ`)。

好了讓我們言歸正傳,為什麼我們不能直接用sort給map排序呢?

這是因為sort演算法只能對序列容器進行排序,就是線性的(如vector,list,deque)。map雖然也是一個集合容器,但是它不是線性儲存的(比如紅黑樹)。因此,我們需要先把map中的元素放到序列容器中,然後再對這些元素進行排序。

根據定義,sort演算法的第3個引數即可以是函式指標,也可以是函式物件(可以以函式方式與()結合使用的任意物件,包括函式名、指向函式的指標和過載了“operator()”操作符的類物件)。

下面的演算法,給出了函式物件的兩種情況。

#include <iostream>
#include <map>
#include <vector>
#include <string>
using namespace std;

typedef pair<string, int> Pair;

//第3引數為函式名
bool my_compare(const Pair &p1, const Pair &p2){
	return p1.second < p2.second;
}

//第3引數為過載了operator()操作符的類物件
struct MyCompare{
public:
	bool operator()(const Pair &p1, const Pair &p2) const{
		return p1.second < p2.second;
	}
};

int main(){
	map<string, int> test;
	test["Alice"] = 3;
	test["Cindy"] = 11;
	test["Bob"] = 7;

	cout << "> sort by key" << endl;
	for(auto itr = test.begin(); itr != test.end(); ++itr){
		cout << itr->first << ": " << itr->second << endl;
	}
	cout << endl;

	vector<Pair> vec;

	for(auto itr = test.begin(); itr != test.end(); ++itr){
		vec.push_back(make_pair(itr->first, itr->second));
	}

	sort(vec.begin(), vec.end(), MyCompare()); //my_compare或者MyCompare()都可以

	cout << "> sort by value" << endl;
	for(auto itr = test.begin(); itr != test.end(); ++itr){
		cout << itr->first << ": " << itr->second << endl;
	}

	return 0;
}

【結果】

> sort by key
Alice: 3
Bob: 7
Cindy: 11

> sort by value
Alice: 3
Bob: 7
Cindy: 11