STL sort函数中Compare类型的实现方式

STL容器排序详解
本文详细介绍了STL容器中的排序方法,包括支持随机访问的容器如vector、deque、string如何使用std::sort进行排序,以及list如何使用list::sort。同时,文章还深入探讨了不同数据类型和复合类型在排序过程中的实现方式。

STL容器的排序,支持随机访问的容器vector,deque,string没有sort成员函数,可调用std::sort排序;list排序调用自带的list::sort

下面是std::sort函数,有两个版本:

template <class RandomAccessIterator>  

  1. void sort ( RandomAccessIterator first, RandomAccessIterator last );  
  2.  
  3. template <class RandomAccessIterator, class Compare>  
  4. void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp ); 

sort函数有以下特征:
1. 要求输入一个范围[first, last)
2. 随机迭代器,能用此算法的容器是支持随机访问的容器:vector, deque, string。  //不支持链表一类的排序。
3.第一个版本使用operator<进行比较,默认升序排序,第二个版本使用comp做比较.  //排序后的结果默认是升序,即1,2,3,4,5这样。

关于参数comp,comp带两个同类型的参数,如果第一个参数排在第二个参数前面,返回true,否则返回false  
它可以是函数指针,也可以是函数对象。函数指针好理解,何谓函数对象?
函数对象(Function Object),是实现了()运算符重载函数的类(或结构体)实例化出来的对象,使用起来像函数,又叫仿函数。


当容器元素为内建类型(即使不为模板类型后面的括号也不要丢)时可以使用,注意使用的格式,要加模版参数(由于是模板类)和后面的(),如下:

sort(vec.begin(), vec.end(), less<int>()); 

对于复合类型,实现排序方式有3种方法:
1) 重载operator<操作符  (可能sort函数默认的比较方法就是依据<运算符的结果,注意是<,而不是>也不是<=。在实现时,如果两个值相等,也应该返回false)
2) 写全局的比较函数,使用其函数指针(调用时参数写函数名即可)
3) 写仿函数,重载operator()形式为:bool operator()(const 类名& 参数){…}   //()运算符被用于比较大小,也是够可以的!这所以不用<运算符,可能是基于不与方法1混淆。

STL本身提供了几个比较函数,下面这些都是仿函数:
less(小于)    这里的less是对应的struct或class 的名称。
greater(大于)
equal_to(等于)
not_equal_to(不相等)
less_equal(小于等于)
greater_equal(大于等于)


下面看看这3种方法的实现:

   // 排序元素,比较的对象

  1. struct Person  
  2. {  
  3.   Person(int id, const string& name, int age): id_(id), name_(name), age_(age)  
  4.   {}  
  5.  
  6. int id_;  
  7.   string name_;  
  8. int age_;  
  9. }; 

 

  1. // 方式1:重载operator<用于排序时的比较(是类的成员函数)
  2. bool operator< (const Person& rt)  
  3. {  
  4. return this->id_ < rt.id_;  
  5. }  
  6.  
  7. // 排序函数写法,默认调用operator<
  8. sort(members.begin(), members.end()); 

 

  1. // 方式2:写比较函数
  2. bool CompAge(const Person& pl, const Person& pr)  
  3. {  
  4. return pl.age_ < pr.age_;  
  5. }  
  6.  
  7. // 排序时传入比较函数指针
  8. sort(members.begin(), members.end(), CompAge); 

 

  1. // 方式3:仿函数
  2. struct CompName  
  3. {  
  4. bool operator()(const Person& pl, const Person& pr)  
  5.   {  
  6.         return pl.name_ < pr.name_;  
  7.   }  
  8. };  
  9.  
  10. // 排序时传入函数对象
  11. sort(members.begin(), members.end(), CompName()); 

用函数对象代替函数指针的优点:
1. 函数对象可以存储中间结果在数据成员中,而函数想要存中间结果须要设全局变量或静态变量,这个是我们不想要的。
2. 在函数对象中编译器可以实现内联调用,从而提升性能。

下面看一个函数对象的扩展应用

// 利用函数对象实现升降排序

  1. struct CompNameEx{  
  2.   CompNameEx(bool asce) : asce_(asce)  
  3.   {}  
  4. bool operator()(const Person& pl, const Person& pr)  
  5.   {  
  6. //《Eff STL》条款21: 永远让比较函数对相等的值返回false,这样的排序才可能是稳定排序。当然是否是稳定的,还与排序算法本身有关。
  7. return asce_ ? pl.name_ < pr.name_ : pr.name_ < pl.name_;  
  8.   }  
  9. private:  
  10. bool asce_;  
  11. };  
  12. // 使用仿函数排序(升降序)
  13. sort(members.begin(), members.end(), CompNameEx(false)); 

注意:如果是指针的容器,比较函数的参数也应是指针。

转载于:https://my.oschina.net/ray1421/blog/685267

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值