STL sort排序算法详细介绍

用于C++中,对给定区间所有元素进行排序。头文件是#include <algorithm>
时间复杂度为n*log2(n)


Sort函数有三个参数:

  1. 第一个是要排序的数组的起始地址。
  2. 第二个是结束的地址(最后一位要排序的地址的下一地址)
  3. 第三个参数是排序的方法,可以是从大到小也可是从小到大,还可以不写第三个参数,此时默认的排序方法是从小到大排序。

第一种方法:

Sort函数使用模板:
Sort(start,end,排序方法)

#include<iostream>  
#include<algorithm>  
using namespace std;  
int main()  
{  
    int a[10]={9,6,3,8,5,2,7,4,1,0};  
    for(int i=0;i<10;i++)  
    cout<<a[i]<<endl;  

    sort(a,a+10);//第三个参数不用写(如果是从小到大排序的话)  

    for(int i=0;i<10;i++)  
        cout<<a[i]<<endl;  
    return 0;  
}  

当从大到小排序是需要借助第三个参数进行判别

#include<iostream>  
#include<algorithm>  
using namespace std;  

bool compare(int a,int b)  
{  
    return a>b;  
}  
int main()  
{  
    int a[10]={9,6,3,8,5,2,7,4,1,0};  
    for(int i=0;i<10;i++)  
        cout<<a[i]<<endl;  
    //从大到小排序    
    sort(a,a+10,compare);//在这里就不需要对compare函数传入参数了, 

    //这是规则  
    for(int i=0;i<10;i++)  
        cout<<a[i]<<endl;  
    return 0;  
}  


第二种方法:

  • 上述方法实现了从小到大排序,从大到小排序,但是有点麻烦,可以利用现有的头文件进行实现(类型支持“<”,”>”等比较符)。
  • functional提供了一种基于模板的比较函数对象,equal_to<Type>、not_equal_to<Type>、greater<Type>、greater_equal<Type>、less<Type>、less_equal<Type>
  • 常用的有greater <Type>()从大到小排序,less <Type>()从小到大排序。

第三种方法:

编写运算符重载函数

<返回类型说明符> operator <运算符符号>(<参数表>)
{

     <函数体>

}

对于这种方法,一般应用于自定义数据类型,因为sort排序函数是应用
<实现功能的。
程序举例:

struct Test
{
  int mem1;
  int mem2;
  bool operator< (const Test t)  
  {  
      return this->mem1<t.mem1;  
  }  
};

当然也可以用第一种方法,自定义比较函数实现!!!

第四种方法:

定义外部比较类:

struct Less
{ 
   bool operator()(const Student& s1, const Student& s2)
       {  
             return s1.name < s2.name; //从小到大排序    
       }
 };
std::sort(sutVector.begin(), stuVector.end(), Less());

sort函数使用

STL提供了两种调用方式,一种是使用默认的<操作符比较,一种可以自定义比较函数。
实现原理:
STL中的sort并非只是普通的快速排序,除了对普通的快速排序进行优化,它还结合了插入排序和堆排序。根据不同的数量级别以及不同情况,能自动选用合适的排序方法。当数据量较大时采用快速排序,分段递归。一旦分段后的数据量小于某个阀值,为避免递归调用带来过大的额外负荷,便会改用插入排序。而如果递归层次过深,有出现最坏情况的倾向,还会改用堆排序。
普通的快速排序可以叙述如下,假设S代表需要被排序的数据序列:


  1. 如果S中的元素只有0或1,结束
  2. 取S中的任何一个元素作为枢轴pivot
  3. 将S分割为L、R两端,使L中的元素都小于等于pivot,R中的元素都大于等于pivot。
  4. 对L、R递归执行上述过程。

快速排序最关键的地方在于枢轴的选择,最坏的情况发生在分割时产生了一个空的区间,这样就完全没有达到分割的效果。STL采用的做法称为median-of-three,即取整个序列的首、尾、中央三个地方的元素,以其中值作为枢轴。

分割的方法通常采用两个迭代器head和tail,head从头端往尾端移动,tail从尾端往头端移动,当head遇到大于等于pivot的元素就停下来,tail遇到小于等于pivot的元素也停下来,若head迭代器仍然小于tail迭代器,即两者没有交叉,则互换元素,然后继续进行相同的动作,向中间逼近,直到两个迭代器交叉,结束一次分割。

看一张来自维基百科上关于快速排序的动态图片,帮助理解。
这里写图片描述
快速排序的口诀:
东拆西补,西拆东补,一边拆一边补,递归完成所有过程
这里写图片描述
对元素5的两边的元素也重复以上操作,直到元素达到有序状态


  • 内省式排序Introsort
    不当的枢轴选择,导致不当的分割,会使快速排序恶化到O(n^2)。David R.Musser于1996年提出一种混合式排序算法:Introspective Sorting(内省式排序),简称IntroSort,其行为大部分与上面所说的median-of-three Quick Sort完全相同,但是当分割行为有恶化为二次方的倾向时,能够自我侦测,转而改用堆排序,使效率维持在堆排序的 O(nlgn),又比一开始就使用堆排序来得好。

  • 17
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值