如果你用C++编码, 需要对容器内的元素进行排序, 这个容器提供任意访问的迭代器, 比如std::vector
, 那么简单快捷的方法是使用里的std::sort
函数.
Basic sorting std::sort
函数需要两个参数, 这两个参数分别指向你要排序的序列容器的开始(initial)和终点(final). 这个序列容易内除final指向的那个元素外 所有元素都会被排序. 下面是一个简单的排序例子:
#include <algorithm>
#include <vector></vector></algorithm>
const int array[] {10, 20, 5, 15, 0};
std::vector<int> vec(array, array + 5);</int>
std::sort(vec.begin(), vec.end());
输出: 0 5 10 15 20
More complex sorting 在某些时候, 根据数值升序排序已经足够解决问题了, 但是当我们需要按某个特定的参数进行排序, 或者降序排列时, 就需要一些其他的东西了. 对于这种需求, std::sort
需要引入第三个参数: 比较函数. 这个比较函数有两个参数, 分别是序列容器的两个元素, 返回值可以隐式地转为bool. 如果第一个参数应该排在第二个参数前面, 则返回true.
例:
#include <algorithm>
#include <vector></vector></algorithm>
bool DescOrderInt(int a, int b);
...
const int array[] = {10, 20, 5, 15, 0};
std::vector<int> vec(array, array + 5);</int>
std::sort(vec.begin(), vec.end(), DescOrderInt);
DescOrderInt的实现:
bool DescOrderInt(int a, int b)
{
return a > b;
}
输出: 20 15 10 5 0
C++11 sort using function objects 网上很多例子说, 为了排列元素, 可以使用std::binary_function
定义比较函数, 但不幸的是, std::binary_function
在C++11 中已经被标为 “将被弃用的”, 在C++17中会被完全移除, 所以写新的C++代码时, 最好不要用这个.
我们可以使用C++11中引入的std::function
来定义这个函数指针. 例:
#include <algorithm>
#include <function>
#include <vector></vector></function></algorithm>
struct StrDescOrderInt
{
bool operator()(int a, int b) const
{
return a > b;
}
};
...
const int array[] = {10, 20, 5, 15, 0};
std::vector<int> vec(array, array + 5);</int>
std::function<bool(int, int)=""> sorter = StrDescOrderInt();</bool(int,>
std::sort(vec.begin(), vec.end(), sorter);
输出: 20 15 10 5 0
A real-life example: providing multiple sorting options 我们假设有一队足球运动员, 我们想让用户按他们自己的意愿去排列这些运动员. 有一个图表的UI, 上面有几个按钮, 每个按钮对应不用的排序规则.
Plaer 类的代码:
// -- Player.h --
#include <string></string>
class Player
{
public:
Player(const char * name, int caps, int goals);
const std::string & GetName() const;
int GetCaps() const;
int GetGoals() const;
private:
std::string mName;
int mCaps;
int mGoals;
};
现在我们新写一个类或结构体来列出所有的比较函数. 比较函数是一个结构体并实现操作符()
, 操作符()
带有两个参数, 分别为两个指向Player的指针, 返回bool值.
class Player;
struct PlayerSorting
{
// name
struct SortPlayerByNameAsc (bool operator()(Player* p1, Player* p2) const;);
struct SortPlayerByNameDes (bool operator()(Player* p1, Player* p2) const;);
// caps
struct SortPlayerByCapsAsc (bool operator()(Player* p1, Player* p2) const;);
struct SortPlayerByCapsDes (bool operator()(Player* p1, Player* p2) const;);
// goals
struct SortPlayerByGoalsAsc (bool operator()(Player* p1, Player* p2) const;);
struct SortPlayerByGoalsDes (bool operator()(Player* p1, Player* p2) const;);
}
然后, 在调用它的地方, 我们可以先把所有的std::function
存在一个std::vector
里, 使用的时候, 用索引访问vector的元素.
std::vector< std::function<bool(player *,="" player="" *)=""> > sorters;
sorters.push_back(PlayerSorting::SortPlayerByNameAsc());
sorters.push_back(PlayerSorting::SortPlayerByCapsAsc());
sorters.push_back(PlayerSorting::SortPlayerByGoalsAsc());
sorters.push_back(PlayerSorting::SortPlayerByNameDes());
sorters.push_back(PlayerSorting::SortPlayerByCapsDes());
sorters.push_back(PlayerSorting::SortPlayerByGoalsDes());</bool(player>
例如, 根据得分降序排列:
std::vector<player *=""> players;</player>
// ...init players...
std::sort(players.begin(), players.end(), sorters[5]);
输出:
NAME CAPS GOALS
Lionel Messi 21 20
David Villa 13 16
Asamoah Gyan 22 15
Arjen Robben 11 12
Mesut Oezil 19 10
Diego Forlan 20 10
Andres Iniesta 15 9
Wesley Sneijder 24 6
Xavi 17 5
Bastian Schweinsteiger 23 4
假如需要实现一种新的排序方式, 我们只需要在PlayerSorting类中添加一个新的仿函数即可.
原文地址: http://blog.davidecoppola.com/2015/01/cpp11-sort-using-function-objects/