前言
上次介绍了几种最简单常用的排序算法,但对于咱们现在这个时代来说,这些算法已经太慢了,几乎没有实用价值,所以这次说一些比较常用实用的更快的排序算法。
还有就是这些算法有的用到了分治的思想。建议去学习一下这种思想,非常有用。
种类
- 希尔排序
- 堆排序
- 归并排序
- 快速排序
希尔排序
关于希尔排序的主要是思想就是跳跃式交换,从而提高了排序的速度,而其跳跃式交换就依赖于其中的一个变量:inc。
我个人认为这是一个非常巧的排序,以至于我不知道这个方法为什么可行(逃···
反正··就是利用这个方法就可以高效的完成排序。
void ShellSort(int *a,int len)
{
int inc=len;
while(inc>1)
{
inc=inc/3+1;//关于这个运算,有很多种其他的算法方法,不止这一种
for(int i=inc+1;i<=len;++i){
if(a[i]<a[i-inc]){
a[0]=a[i];
int j;
for(j=i-inc;j>0&&a[0]<a[j];j-=inc)//跳跃式交换
a[j+inc]=a[j];
a[j+inc]=a[0];//腾出的位置给a[i]
}
}
}
print(a,len);
}
堆排序:
关于堆的定义这里就不在赘述了,反正大家都知道。
我写的这个堆排序和书上的有些不一样,区别在于每次都从倒数第二层开始进行根节点的调整,而不是从上往下进行调整,我觉得那样过于麻烦,而且也没有比我这个快多少。
并且我这个排序的空间利用率也是O(1)的
void HeapAdJust(int *a,int num)//调整数组,使其符合堆的定义
{
for(int i=num/2;i>=1;--i){
if(a[i]<a[i*2])
Swap(a[i],a[i*2]);
if(a[i]<a[i*2+1])
Swap(a[i],a[i*2+1]);
}
}
void HeapSort(int *a,int n)
{
int b;
for(int i=1;i<=n;++i){
HeapAdJust(a,n-i+1);//注意这块的n-i+1,代表之后的数就不考虑了,认为已经被挪走
b=a[1];
a[1]=a[n-i+1];
a[n-i+1]=minl;//把最小的交换到堆顶
a[n-i+2]=b;//重要的地方,如果不是+2的话,会因为调整函数不知道这个是已经从堆顶拿走的数据,而导致出现错误,所以整体后移一格
}
print(a+1,n);//最后输出也是整体后移一格
}
下面的排序用到了分治的思想
归并排序
就是把一个序列分成两个序列,一直分下去知道序列里只有一个值。然后进行合并,合并时就和两个有序数列的合并一样,没有难度。
其归并的思想在于将一个大序列有序转换成多个小序列有序,分而治之。从而简化问题,当只有一个值时,其答案是显而易见的
void Merge(int *a,int f,int mid,int r,int *b)//区间的合并
{
int pa1=f,pa2=mid+1,pb=0;
while(pa1<=mid&&pa2<=r)
{
if(a[pa1]<a[pa2])
b[pb++]=a[pa1++];
else
b[pb++]=a[pa2++];
}
while(pa1<=mid)
b[pb++]=a[pa1++];
while(pa2<=r)
b[pb++]=a[pa2++];
for(int i=0;i<pb;++i)
a[f+i]=b[i];
}
void MergeSort(int *a,int f,int r,int *b)
{
if(f<r){
int mid=(f+r)/2;
MergeSort(a,f,mid,b);//每次分成两个区间
MergeSort(a,mid+1,r,b);
Merge(a,f,mid,r,b);
}
}
快速排序
每次寻找一个key值,然后对区间进行操作。使其在区间中的位置为:在key之前的都比key小,在key之后的都比key大。然后再将这前后两个序列进行上述步骤。
快排所利用的也是分治的思想,将大区间转化为小区间,而每两个小区间的值不存在交叉的问题,所以效率非常的高。
void QuickSort(int *a,int f,int r)
{
if(f>=r)
return ;
int i=f;
int j=r;
int k=a[i];
while(i!=j)//把key值放到合适的位置
{
while(i<j&&a[j]>k)
--j;
if(i<j)
Swap(a[i],a[j]);
while(i<j&&a[i]<k)
++i;
Swap(a[i],a[j]);
}//a[i]=k
QuickSort(a,f,i-1);//分成两个区间,分别操作
QuickSort(a,i+1,r);
}
总结
其实这些排序想明白了也很好理解,并且灵活运用这些算法对将来的很多问题也会有很大的帮助。虽然STL中有现成的sort函数,但自己敲出来的收获肯定是比直接调用STL的收获要大的。
并且这些排序也能告诉我们,想要做出进步,就必须突破原有的思维限制,勇于尝试新的东西。