希尔排序是Donald Shell于1959年提出来的一种排序算法,它是第一批突破
这个时间复杂度的算法之一。大话数据结构对这个算法的讲解,我看得只知其一;不知其二的,以后网上找了下资料,发现维基百科对这个算法的讲解很是不错,特在此整理一波。算法
希尔排序是基于插入排序的如下两点性质而提出改进方法的:数组
先上个维基百科的动图,不知道大家看不看得懂,反正我不是很懂……bash
说说个人我的理解:数据结构
希尔排序其实就是直接插入排序的升级,原理就是先将整个待排序列按照某个增量(也称步长)分割成若干个子序列分别进行直接插入排序,而后合并,以后依次缩小增量大小在进行排序,当增量足够小(一般为1)时,再对全体元素进行直接插入排序,而此时需排序的数据几乎是已排好的了,因此此时插入排序较快。ui
固然若是你以为文字比较乏味就看下面的这些例子吧spa
例如,假设有这样一组数[9 1 5 8 3 7 4 6 2]
,若是咱们先以步长为4进行分割,就是这样:.net
9 1 5 8
3 7 4 6
2
复制代码
而后咱们对每列进行排序(注意每列哦):3d
2 1 4 6
3 7 5 8
9
复制代码
将上述四行数字,依序合并咱们获得:[ 2 1 4 6 3 7 5 8 9 ]
。此时2已经往前移,而八、9已经在后两位,而后再以2为步长进行分割:code
2 1
4 6
3 7
5 8
9
复制代码
继续排序:cdn
2 1
3 6
4 7
5 8
9
复制代码
合并获得[ 2 1 3 6 4 7 5 8 9]
,此时序列已经基本有序,需交换数据的状况大为减小,这时整列进行直接插入排序效率就很是高。
最终完成排序过程,也就是步长为1时,获得最终序列为:1 2 3 4 5 6 7 8 9
。
#include <stdio.h>
#define MAXSIZE 100 //用于要排序数组的最大值
typedef struct //定义一个顺序表结构 {
int r[MAXSIZE+1]; //用于存储要排序数组,r[0]用做哨兵或者临时变量
int length; //用于存储顺序表的最大长度
}SqList;
void ShellSort(SqList *L) {
int i,j;
int gap=L->length; //获取数组长度
for(gap/=2;gap>=1;gap/=2) //步长
for(i=gap+1; i<=L->length; i++) //从第gap+1个元素开始,由于r[0]被当作临时变量
if(L->r[i] < L->r[i-gap]) //每一个元素与本身组内的数据进行直接插入排序
{
L->r[0]=L->r[i]; //把要交换的数据暂存的L->r[0]中
for(j=i-gap; j>0&&L->r[j] > L->r[0]; j-=gap)
L->r[j+gap] = L->r[j]; //记录后移,查找插入位置
L->r[j+gap]=L->r[0]; //插入
}
}
int main() {
int i=0;
int array[] = {39,80,76,41,13,29,50,78,30,11,100,7,41,86};
SqList L;
L.length = sizeof(array)/sizeof(array[0]); //获取数组长度
for(i=0;i<L.length;i++)
{
L.r[i+1]=array[i]; //把数组存入顺序表结构
}
ShellSort(&L);
//输出排序后的数组
for(i=0;i<L.length;i++)
{
printf("%d ",L.r[i+1]);
}
return 0;
}
复制代码
可能有几个步骤略难懂,这里解释下:
第17行:这里的步长采用,最终判断条件为gap>=1,这里无论你数组初始长度为多少,除到最后均会等于1,而等于1时,就是执行最后一次循环,这个时候也就是全部元素进行直接插入排序。固然也可写成gap>0。
第18行:在前面定义顺序表结构时,咱们加多了一位,也就是把r[0]当作交换数据时的临时变量。
第22~23行:对于这个循环咱们直接拿上面的例子中的一列进行讲解(9 3 2)
:
当时,9和3进行了一次交换,变为
(3 9 2)
(位置为1 5 9),以后在时
,作出的交换如上图所示(图略差...),分为三个步骤:
(3 9 9)
;(3 3 9)
;(2 3 9)
。步长的选取很是关键,可是步长的选择没有统一规定,也没绝对的规律。只要知足最后一个步长为1便可。Donald Shell最初建议步长选择为,虽然这样去能够比
类的算法更好,但仍然有减小平均时间和最差时间的余地。维基百科给出的部分步长与最坏状况下复杂度有:
已知的最好步长序列是由Sedgewick提出的(1, 5, 19, 41, 109,...),该序列的项来自和
这两个算式。这项研究也代表“比较在希尔排序中是最主要的操做,而不是交换。”用这样步长序列的希尔排序比插入排序要快,甚至在小数组中比快速排序和堆排序(后续博客整理),可是在涉及大量数据时希尔排序仍是比快速排序慢。