希尔排序
ShellSort,排序算法史上的里程碑。
为什么这么说呢?因为在这之前,人类一直没法有效突破排序算法时间复杂度,大O长时间停留在n平方。而希尔排序做到了。
它是怎么实现的?通过一种巧妙的思路:设置增量,逐渐有序。
什么叫逐渐有序?比如,可以回想一下插入排序。它的操作是很绝对的,过程中一旦插入,就要保证前序列的绝对有序。如果是升序,你就不可能把4插到5的后面。但是希尔排序在进行一次遍历后,往往只是更有序了一点。它不强调每次操作的绝对性,而是讲究循序渐进。
至于增量,是关于遍历次数变量,也是一个至今没有定论的变量。
值得注意的是,增量最后要等于1。
待排序数据依然存放于顺序表中。
数据存放没有从0开始,而是选择从1开始。
代码参考于《大话数据结构》。
初始设定
#include<stdio.h>
#define MAXSIZE 20 //顺序表最大容量
#define N 10 //表中数据个数
顺序表结构体
typedef struct
{
int data[MAXSIZE + 1];
int len; //已存储元素个数
}Sqlist;
输出顺序表
void Show(Sqlist L)
{
int i;
for (i = 1; i < L.len; ++i)
{
printf("%d,", L.data[i]);
}
printf("%d\n", L.data[i]);
}
输入函数
void Input(Sqlist* lp)
{
int d[N] = { 9, 1, 5, 8, 3, 0, 7, 4, 6, 2 };
for (int i = 0; i < N; i++)
lp->data[i + 1] = d[i];
lp->len = N;
}
希尔排序
void ShellSort(Sqlist* lp)
{
int i, j, k = 0;
int increment = lp->len;
do
{
increment = increment / 3 + 1; //增量序列
for (i = increment + 1; i <= lp->len; ++i)
{
if (lp->data[i] < lp->data[i - increment])
{
lp->data[0] = lp->data[i]; //暂存
for (j = i - increment; j>0 && lp->data[0] < lp->data[j]; j -= increment)
lp->data[j + increment] = lp->data[j];
lp->data[j + increment] = lp->data[0]; //插入
}
}
printf(" 第%d趟排序结果:", ++k);
Show(*lp);
} while (increment>1);
}