下面总结一些常见的高效的排序算法。
1. 归并排序
- 主要思想:递归排序+合并。
- 复杂度:
O(NlogN)
。好写速度快,不容易卡。
int a[10]={0,2,9,1,7,8,5,3,4,2},T[10];
void Msort(const int L,const int R)
{
if (R-L<=1) {if (a[L]>a[R]) swap(a[L],a[R]); return;}
//两个数时可以直接比较,常数更小
Msort(L,(L+R)>>1); Msort(((L+R)>>1)+1,R);//递归排序
x=L; y=((L+R)>>1)+1; p=0;//初始化指针(用普通整数模拟,指针应该更快)
while (x<=((L+R)>>1)&&y<=R)
if (a[x]<a[y]) T[++p]=a[x++];
else T[++p]=a[y++];
while (x<=((L+R)>>1)) T[++p]=a[x++];
while (y<=R) T[++p]=a[y++];
for (register int i=1; i<=p; i++)
a[i-1+L]=T[i];//数组还原,T我使用了全局数组
}
Msort(1,N);
2. 快速排序
- 主要思想:找基准数+递归排序
- 复杂度:
O(NlogN)
,稍微难写,容易卡(如果快排能过当然都用sort了),没有归并实用。
void Qsort(const int L,const int R)
{
if (R-L<=1) {if (a[L]>a[R]) swap(a[L],a[R]); return;}
swap(a[L],a[rand()*rand()%(R-L+1)+L]);//打乱
x=L; y=R; k=a[L];
while (x<y)
{
while (a[y]>=k&&x<y) y--; a[x]=a[y];
while (a[x]<=k&&x<y) x++; a[y]=a[x];
}
a[x]=k; Qsort(L,x); Qsort(x+1,R);
}
Qsort(1,N);
为了防止被卡,我采取的办法是把a[L]
与之后本区间一个随机数交换的方法,好写但不保险。
3. 基数排序
- 主要思想:二进制划分数 & 桶排序扩展
- 复杂度:
O(kN)
,不过据说int
划成4段要比两段快,看机型吧。浮点基排本蒟蒻不会。高端大气且效率较高,代码量也不大,但是一般只排整数。
void Rsort()
{
//这里是int划分为两段的低位向高位排序,从高到低的话效率应该差不多。
register int i=0;
for (i=1; i<=N; i++) T[(a[i]&0xffff)+1]++;
for (i=1; i<=0xffff; i++) T[i]+=T[i-1];
for (i=1; i<=N; i++) b[++T[(a[i]&0xffff)]]=a[i];//先按照后16位划分重排
memset(T,0,sizeof(T));
for (i=1; i<=N; i++) T[(b[i]>>16)+1]++;
for (i=1; i<=0xffff; i++) T[i]+=T[i-1];
for (i=1; i<=N; i++) a[++T[(b[i]>>16)]]=b[i];//再按照前16位划分重排。
}
基数排序的板子和变种我还不是特别熟,以后考试遇到的话可以多练一下。
4. 总结
- 堆排序也有很多优点,但是难于上手,没时间复习,先不写了。
- 做题时碰到要排序的情况一定要先思考有没有更好的排序方法,不要盲目打
sort
,也许有更、适合的排序方法降低复杂度