四.希尔排序
希尔排序其实是插入排序的优化版本
回忆下直接插入排序算法,在初始序列是正序(递增)的时候,时间复杂度为O(N),在初始序列是逆序(递减)的时候,时间复杂度是O(N^2)。
由此设想,如果初始序列“基本有序”,那么直接插入排序的性能就会提高那么怎么让序列基本有序呢?如果有一种操作让混乱的序列基本有序,那么会不会把已经排好的序列打乱,反而将事情变的复杂了。
希尔排序算法就是将初始序列分成几个序列,然后将差分的序列排好
拆分的方式就是——间隔
下面再来对这个数组使用希尔排序法进行排序
int a[] ={49 ,38 ,65 ,97 ,76 ,13 ,27 ,49}
- 第一趟:49 13 27 49 76 38 65 97 间隔为4
- 第二趟:27 13 49 38 65 49 76 97 间隔为2
- 第三趟:13 27 49 49 38 65 76 97 间隔为1
在每一趟排序过程中,其实使用的还是直接插入排序,相当于使用了三次插入排序
就是说,将原来的序列分为几个序列,对每个序列使用插入排序。然后减少序列的个数(缩小间隔),再对每个序列使用插入排序,直到间隔为1。
下面我们看看如何使用代码实现
void ShellSort(ElementType a[],int N)//希尔排序
{
int D,P,i,temp;
for(D=N/2;D>0;D/=2){//增量序列
//由间隔D可以分出一个序列,对于每个序列,使用直接插入排序
for(P=D;P<N;++P){//直接插入排序
temp = a[P];
for(i=P;i>=D&&a[i-D]>temp;i-=D){//如果前面的元素大于temp,那么temp一定在更前面
a[i] = a[i-D];//前面元素后移,为temp腾出位置
}
a[i] = temp;//找到合适的位置并插入元素
}
}
}
分析:
希尔排序的分析是个复杂的问题,涉及数学上一些为解决的难题,我们知道在最坏情况下,希尔排序的时间复杂度为 O(N^2)。