C++11 sort using function objects

如果你用C++编码, 需要对容器内的元素进行排序, 这个容器提供任意访问的迭代器, 比如std::vector, 那么简单快捷的方法是使用里的std::sort 函数.

Basic sorting
std::sort 函数需要两个参数, 这两个参数分别指向你要排序的序列容器的开始(initial)和终点(final). 这个序列容易内除final指向的那个元素外 所有元素都会被排序.
下面是一个简单的排序例子:

#include <algorithm>
#include <vector>

const int array[] {10, 20, 5, 15, 0};
std::vector<int> vec(array, array + 5);

std::sort(vec.begin(), vec.end());

输出:
0 5 10 15 20

More complex sorting
在某些时候, 根据数值升序排序已经足够解决问题了, 但是当我们需要按某个特定的参数进行排序, 或者降序排列时, 就需要一些其他的东西了.
对于这种需求, std::sort 需要引入第三个参数: 比较函数. 这个比较函数有两个参数, 分别是序列容器的两个元素, 返回值可以隐式地转为bool. 如果第一个参数应该排在第二个参数前面, 则返回true.

例:

#include <algorithm>
#include <vector>

bool DescOrderInt(int a, int b);
...
const int array[] = {10, 20, 5, 15, 0};
std::vector<int> vec(array, array + 5);

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>

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);

std::function<bool(int, int)> sorter = StrDescOrderInt();

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>

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());

例如, 根据得分降序排列:

std::vector<Player *> players;

// ...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/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值