在介绍排序算法前,先说明一个可以称为排序准则的东西,也就是定义strict weak ordering,其意义如下:
1.必须是非对称的,对operator < 而言,如果x<y是true,则y<x为false。对判断式op()而言,若op(x,y)为true,则op(x,y)为false。
2.必须是可传递的,对operator < 而言,如果x<y是true且y<z为true,则x<z为true。对判断式op()而言,若op(x,y)为true且op(y,z)为true。
op(x,z)为true。
3.必须是非自反的,对operator < 而言,x<x永远是false。对判断式op()而言,op(x,x)永远为false。
4.必须具有等效传递性,大致上来说就是如果a==b&&b==c,那么a=c。
STL的排序算法
stl提供了几种算法来对区间内的元素排序,一般分为完全排序(full sorting)和局部排序(partial sorting)。在可以达到使用目的的情况下,优先使用后者,因为其效能更高。但由于一些关联式容器(set,map)和无序容器等不提供random-access iterator,所以不适用于这些排序算法。
但值得注意的是,对全体元素进行一次性排序通常比”始终维护它们保持排序状态“效率要高,所以具体使用何种容器还要看你所需要的是什么。
排序算法头文件
#include<algorithm>
1.完全排序
void sort(random_access_iterator_beg,random_access_iterator_end) void sort(random_access_iterator_beg,random_access_iterator_end,binary_predicate op) void stable_sort(random_access_iterator_beg,random_access_iterator_end) void stable_sort(random_access_iterator_beg,random_access_iterator_end,binary_predicate op)
- 在这里有sort()和stable_sort(),它们默认的第一形式都是用operator < 对区间[beg,end)内的所有元素排序。
- sort()和stable_sort()的第二形式使用binary predicate作为排序准则,也就是使用者自己去定义的排序准则。
- 注意,op必须针对元素值定义出strict weak ordering,也就是本文开篇所介绍的内容。
- sort()与stable_sort()的区别在于,后者更加稳定,保证相等的元素的相对次序在排序后不发生改变。
时间复杂度:
sort():平均复杂度nlogn,最坏n^2。
stable_sort():若内存足够,则就是nlogn,不会变化。若没有足够内存,则复杂度是2nlogn。
比较常用的sort结构体排序
#include<iostream> #include<algorithm>
using namespace std; struct node { int num1,num2; }arr[10000]; bool cmp(node a,node b)//自定义比较准则
{ return a.num1<b.num1;//以num1较小者优先排列
} int main() { arr[0]={1,2}; arr[1]={2,1}; arr[2]={3,4}; arr[3]={4,3}; sort(arr,arr+4,cmp);//严格按照要求传入参数
for(int i=0;i<4;++i) { cout<<arr[i].num1<<" "; } cout<<endl; for(int i=0;i<4;++i) { cout<<arr[i].num2<<" "; }
return 0; }
2.局部排序
void partial_sort(random_access_iterator_beg,random_access_iterator_sortend,random_access_iterator_end) void partial_sort(random_access_iterator_beg,random_access_iterator_sortend,random_access_iterator_end,binary_predicate op)
- 第一形式以operator < 对[beg,end)区间内元素进行排序,使[beg,sortend)区间内元素处于有序状态。
- 第二形式使用binary predicate作为排序准则,也就是使用者自己去定义的排序准则。
- 除了与sort所需要注意的相同外,partial_sort()并不对全部元素排序,你传入的参数分别是排序首部,排序尾部,整体区间尾部。它会按照你所指示的区间进行排序,不用进行多余的操作。
- 如果sortend等于end的话,那么partial_sort()会对整个序列排序,平均而言其性能不及sort(),但最差情况则优于sort()。
时间复杂度:在线性与nlogn之间。
3.根据第n个元素排序
void nth_element(random_access_iterator_beg,random_access_iterator_nth,random_access_iterator_end) void nth_element(random_access_iterator_beg,random_access_iterator_nth,random_access_iterator_end,binary_predicate op)
两种形式都对[beg,end)区间内的元素排序,使第n个位置上的元素就位,也就是说,在位置n之前的元素都小于等于它,所有之后的元素都大于等于它。这样,你就得到了”根据n位置上的元素“分割开来的两个子序列,第一子序列的元素统统小于第二子序列的元素,但是处于无序状态。同样的,该算法也提供自定义排序准则。
时间复杂度:平均为线性。
nth_element操作举例
#include<iostream> #include<algorithm>
bool cmp(int a,int b) { return a>b; } using namespace std; int main() { int a[]={1,5,6,2,9,7,3,4,10,8}; int elem=a[2]; nth_element(a, a+3, a+10);//第一种形式,默认为<
int i=0; while(a[i]<elem) { cout<<a[i]<<" "; i++; } cout<<endl; int b[]={1,5,6,2,9,7,3,4,10,8}; nth_element(b,b+3,b+10,cmp);//传入重载函数
int j=0; while(b[j]>elem) { cout<<b[j]<<" "; j++; } }
运行结果
由此可见虽然分割出了序列,但顺序是打乱的。