最近喵哥遇到一個問題:如何在不借助額外空間(新建vector等)來實現map自己的想法(不只是表面的升序、降序)排序(sort只適用於順序容器,map並不可以使用)。
如果忽略“不借助額外空間這個要求”,完全可以用一個vector來實現:
#include <iostream>
#include <map>
#include <algorithm>
#include <functional>
#include <string>
#include <vector>
#include <list>
bool secSort(pair<string, int> const x, pair<string, int> const y) {
return x.second > y.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));
//藉助vector實現map按照second排序
vector<pair<string, int>> vecm(name_score_map.begin(), name_score_map.end());
sort(vecm.begin(), vecm.end(), secSort());
return 0;
}
什麼是仿函數?
仿函數(functors)在C++標準中採用的名稱是函數對象(function objects)。仿函數主要用於STL中的算法中,雖然函數指針雖然也可以作爲算法的參數,但是函數指針不能滿足STL對抽象性的要求,也不能滿足軟件積木的要求–函數指針無法和STL其他組件搭配,產生更靈活變化。仿函數本質就是類重載了一個operator(),創建一個行爲類似函數的對象。
使用仿函數必須包含:<functional>頭文件。先看看STL的一個仿函數,less<_Ty>
template<class _Ty = void>
struct less
{ // functor for operator<
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty first_argument_type;
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty second_argument_type;
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef bool result_type;
constexpr bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator< to operands
return (_Left < _Right);
}
};
乍一看,挺麻煩的,其實只要抓住幾個要點就可以自定義仿函數了:
- 仿函數的類必須重載operator()運算符;
- 重載operator()運算符時必須在函數聲明後面const,即是一個常量成員函數,這是因爲定義的類要跟binder2nd 一致,binder2nd 的 operator() 後面有個 const;
實例
#include <iostream>
#include <map>
#include <algorithm>
#include <functional>
#include <string>
#include <vector>
#include <list>
class secSort {
public:
bool operator() (string x, string y)const {
return x.length() > y.length();
}
};
int main()
{
map<string, int, secSort> 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));
return 0;
}
上面代碼中的secSort就是一個仿函數,在定義仿函數類的時候可以不表明繼承了binary_function與unary_function,其實在編譯的時候可以自動識別出,一個現象就是:如果重載operator()時不是常量成員函數,那麼就會報錯。
上述仿函數實現的是:按照key(string類型)的長度大小排序。如果要實現按照value排序,可以直接在secSort類中把重載函數的參數改爲int嗎?這是絕對不可以的,因爲map默認是按照key值排序的。
事實上,STL中pair的排序方式決定了map的排序。
template<class _T1, class _T2>
inline 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); }
STL源碼中pair已經重載了<號,所以不可以在定義map的時候按照value排序,但是可以參照第一段代碼用vector實現按照value排序。