相关概念
-
希尔排序,又叫做
缩小增量排序
。 -
希尔排序的基本思想
每一趟将整个待排序记录
分成若干子序列
,在每个子序列
内进行直接插入排序
,使每个子序列内有序
。若干趟后,对整个记录序列
进行直接插入排序
。
对待排记录先做宏观调整
,再做微观调整
。
比较过程使用的间隔dk
,由大变小,即是宏观到微观的过程
。 -
宏观调整
指的是>跳跃式</font的插入排序。
具体做法
:将整个记录序列
分成若干子序列
,分别对每个子序列
进行插入排序
。 -
希尔排序的优越性
省的让关键字特别小的记录
只能一个单位一个单位的前移(希尔排序中可以一步跨若干个单位)。
增量逐渐减小(从宏观到微观),直到1。
如 选择增量为5,3,1 ...
比较完成。每一趟里面仍然是插入排序
,只是比较间隔
为 dk。
d=1 时进行比较移动,此时的记录序列
已经很接近于非递增序
了,要移动的次数
很少。
为什么希尔排序完虐直接插入排序 -
增量序列可以有多种取法,但一定要确保
增量序列中的值
没有除 1 以外的公因子
,并且序列的最后一个值
为 1。
算法
// 一趟希尔排序算法,dk是本轮希尔排序所选用的增量
// 也可以看作直接插入排序的查找算法,只是间隔为 dk。
void ShellInsert(SqList &L, int dk)
{
for(i=dk+1; i<=L.length; i++)
{
if(L.r[i].key < L.r[i-dk].key)
{
L.r[0] = L.r[i]; // 暂存
for(j = i-dk;
j>0 && L.r[0].key<L.r[j].key;
j -= dk)
{
// 记录跳跃式移动
L.r[j+dk] = L.r[j];
}
L.r[j+dk] = L.r[0];
}
}
}
// 希尔排序
void ShellSort(SqList &L, int dlta[], int t)
{
// 按增量序列 dlta[0 .. t-1]做希尔排序
for(k=0; k<t; k++)
{
ShellInsert(L, dlta[k]);
}
}
性能分析(,希尔排序)
-
直接插入排序,折半插入排序,表插入排序的
时间复杂度
是 O(n2)。
折半插入排序法中的比较操作的时间复杂度
是O(nlogn) -
希尔排序的时间复杂度 比 n2 要小。
但想要具体分析出希尔排序的时间复杂度十分困难,因为其是 所取增量序列 的函数。
在大量的实验基础上可以得到:当 n 在某个特定范围内,希尔排序所需的比较和移动的次数约为 n1.3 ,当 n -> ∞ 时,可以减少到 n(log2n)2 。