最近喵哥遇到一个问题:如何在不借助额外空间(新建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排序。