1. 程式人生 > >c++對map進行排序

c++對map進行排序

最近在PAT刷題,其中一道題月餅 (25)需要用到對價格進行排序,但是排序後要用到價格對應的總售價。因而可以考慮用關聯容器進行求解,map是比較合適這題的資料結構。

        map是用來存放<key, value>鍵值對的資料結構,可以很方便快速的根據key查到相應的value。關於map的詳細定義及用法可以見C++STL之map學習。假如儲存學生和其成績,我們用map來進行儲存就是個不錯的選擇。 我們這樣定義map<string, int>,其中學生姓名用string型別,作為Key;該學生的成績用int型別,作為value。我們可以根據學生姓名快速的查詢到他的成績。另一方面,如果我們想把所有同學和他相應的成績都輸出來,並且按照我們想要的順序進行輸出:比如按照學生姓名的順序進行輸出,或者按照學生成績的高低進行輸出。換句話說,我們希望能夠對map進行按Key排序或按Value排序。本文對這兩種排序進行一個簡單的總結。

一、按Key排序

       我們知道,map內部本身就是按序儲存的(比如紅黑樹),這樣方便實現快速查詢。在我們插入<key, value>鍵值對時,map就會自動按照key的大小順序進行儲存。因而作為key的型別必須能夠進行大小運算的比較。比如int、double、string、char等型別。以月餅 (25)這一題為背景例子進行程式設計說明。

//按Key排序
#include<iostream>
#include<vector>
#include<map>
#include<iomanip>

using namespace std;  

int main()
{
	double N,maxneed,tm,ts;
	cin>>N>>maxneed;
	vector<double> vm,vs,vp;//vm是總量,vs是總銷售額,vp是價格
	for(int i = 1;i<=N;++i)
	{
		cin>>tm;
		vm.push_back(tm);
	}
	for(int i = 1;i<=N;++i)
	{
		cin>>ts;
		vs.push_back(ts);
	}
	for(int i = 0;i<N;++i)
		vp.push_back(vs[i]/vm[i]);

	map<double,double> m;
	for(int i = 0;i<N;++i)
		m.insert(make_pair(vp[i],vs[i]));//插入後自動按Key值進行排序
	cout<<"按Key排序結果:"<<endl;
	for(map<double,double>::iterator it=m.begin();it!=m.end();++it)
		cout<<it->first<<" "<<it->second<<endl;

	system("pause");
	return 0;
}

結果如下:


       從結果可以看到未對map進行任何操作,它按照Key值自動進行了排序。

       另舉一例進行說明:

#include<iostream>
#include<map>  
#include<string>  
  
using namespace std;  
  
typedef pair<string, int> PAIR;  
  
ostream& operator<<(ostream& out, const PAIR& p) 
{  
	return out << p.first << "\t" << p.second;  
}  
  
int main() 
{  
	map<string, int> 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<string, int>::iterator iter = name_score_map.begin();  
		iter != name_score_map.end();  
		++iter) {  
		cout << *iter << endl;  
	}  
	system("pause");
	return 0;  
 } 
結果如下:


上面的按key值排序有個缺點:即當插入的有多個相等的值時,由於key的唯一性,會只保留一個。因此月餅 (25)這一題不適合用按key進行排序求解(因為不排斥某兩種月餅的價格相等)。

二、按Value排序

        如何實現Map的按Value排序呢?

        第一反應是利用STL中提供的sort演算法實現,這個想法是好的,不幸的是,sort演算法有個限制,利用sort演算法只能對序列容器進行排序,就是線性的(如vector,list,deque)。map是一個集合容器,它裡面儲存的元素是pair,但是它不是線性儲存的(像紅黑樹),所以利用sort不能直接和map結合進行排序。因而可以採用一些其它的思路,總結如下:


思路1:可以考慮將value作為key值進行自動排序。

思路2:可以把map中的key值和value值分別轉存到一個pair型別的vector中,在對vector按照一定的規則排序即可。這樣的方法對值一樣的情況也能夠使用。具體程式碼如下:

//功能:輸入單詞,統計單詞出現次數並按照單詞出現次數從多到少排序  
#include <iostream>
#include <cstdlib>  
#include <map>  
#include <vector>  
#include <string>  
#include <algorithm>  

using namespace std;
   
int cmp(const pair<string, int>& x, const pair<string, int>& y)  
{  
	return x.second > y.second;  
}  
   
void sortMapByValue(map<string, int>& tMap,vector<pair<string, int> >& tVector)  
{  
	for (map<string, int>::iterator curr = tMap.begin(); curr != tMap.end(); curr++)   
		tVector.push_back(make_pair(curr->first, curr->second));    
   
	sort(tVector.begin(), tVector.end(), cmp);  
}  
int main()  
{  
	map<string, int> tMap;  
	string word;  
	while (cin >> word)  
	{  
		pair<map<string,int>::iterator,bool> ret = tMap.insert(make_pair(word, 1));  
		if (!ret.second)  
			++ret.first->second;  
	}   
   
	vector<pair<string,int>> tVector;  
	sortMapByValue(tMap,tVector);  
	for(int i=0;i<tVector.size();i++)  
		cout<<tVector[i].first<<": "<<tVector[i].second<<endl;  
   
	system("pause");  
	return 0;  
}  

結果如下:


參考資料