(写于July 16th, 2013)
最近看起了排序算法,从简单的希尔排序着手,希尔排序又称为“缩小增量排序”(Diminishing Increment Sort),是由希尔在1959年提出的。希尔排序是对插入排序的的一种改进,在效率上有较大的提高。
希尔排序的基本思想是:设定一个元素间隔增量gap,将参与排序的序列按照这个间隔数gap从第一个元素开始一次分成若干个子序列,在子序列中可按照其他方法排序(如冒泡排序)。然后缩小增量gap,重新将整个序列按照新的间隔数gap进行划分,再分别对每个子序列进行排序。如此将“缩小增量gap——划分序列——将每个子序列排序”操作进行下去,知道间隔数增量gap=1为止(一般情况gap缩小到1时,序列大都几乎已经按值有序)。
例如:元素序列{3, 6, 4, 12, 11, 10, 8, 9}
当gap=4时:子序列1:3——11
子序列2:6——10
子序列3:4——8
子序列4:12——9
第一趟排序,gap=4:{3, 6, 4, 9, 11, 10, 8, 12}
第二趟排序,gap=2:{3, 6, 4, 9, 8, 10, 11, 12}
第三趟排序,gap=1:{3, 4, 6, 8, 9, 10, 11, 12}
以下是此算法程序:
#include <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
void shellsort(int k[], int n);//希尔排序函数
int main(int argc, char *argv[])
{
int k[] = {'\0', 3, 6, 4, 12, 11, 10, 8, 9};
int n = 8;
shellsort(k, n);
return EXIT_SUCCESS;
}
void shellsort(int k[], int n)
{
int i, j, flag, temp, gap = n;
/*缩小增量,每次减半,子序列使用冒泡排序*/
while (gap>1)
{
gap = gap / 2;
do
{
flag = 0;
for (i = 1; i <= n - gap; i++)
{
j = i + gap;
if (k[i]>k[j])
{
temp = k[i];
k[i] = k[j];
k[j] = temp;
flag = 1;
}
}
}while (flag != 0);
}
for (i = 1; i <= n; i++)
{
printf("%d\t",k[i]);
}
printf("\n");
}
希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比o(n^2)好一些。由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。
希尔排序算法的速度是一系列增量gap的函数,要对希尔排序的算法做出准确的分析并不容易,如何选取最合适的间隔数序列才能达到最优的排序效果是至今尚未解决的数学难题。