前四篇也是插入排序,他是对简单插入排序的一个优化希尔排序。
简单插入排序效率不高的原因是只比较相邻的两个元素,而希尔排序正是通过扩大比较的范围来提升效率。
希尔排序的基本原理是,将待排序的一组元素按一定间隔分为若千个序列,分别进行插入排序。
开始时设置的“间隔”较大,在每轮排序中将间隔逐步减小,直到“间隔”为1,也就是最后一步是进行简单插人排序。
希尔排序将“间隔”定义为一组增量序列,用来分割待排序列,即将位置之差等于当前增量的元素归属于同一个子序列,并分别进行插人排序;排好后再选取下一个增量,划分子序列再次
排序,直到最后一个增量(一般为1)。
算法实现(C#):
public static void ShellSort(int[] arr)
{
// 希尔排序是对插入排序的改进
// 希尔排序增加每次交换的间隔已达到优化的目的
// 经过前面增量的排序后边的序列就趋近于有序,因此增加了排序效率
int si, d, p, i, tmp;
// 增量序列,增量序列可以有不同的选取规则
int[] sedgewick = new[] { 929, 505, 109, 41, 19, 5, 1, 0 };
// 初始的增量不能超过序列的长度
for (si = 0; sedgewick[si] >= arr.Length; si++) ;
for (d = sedgewick[si]; d > 0; d = sedgewick[++si])
{
// 插入排序
for (p = d; p < arr.Length; p++)
{
tmp = arr[p];
for (i = p; i >= d && arr[i - d] > tmp; i -= d)
arr[i] = arr[i - d];
arr[i] = tmp;
}
}
}
由该算法代码可以看出,空间复杂度上,和简单插入排序一样,希尔排序只需要O(1)的额外空间;
时间复杂度上,每一次针对某增量进行插入排序,随着增量逐渐变小,整体序列逐渐有序起来,每次插入排序的比较和交换次数变少。
希尔排序算法的整体时间复杂度和增量序列的选取有关,目前并没有统一的最优增量序列。
当使用增量序列{[N/2],[N/22],…,1]}进行希尔排序时,最差情况下时间复杂度为0(N2);
当使用增量序列{2k-1,…,7,3,1]}进行希尔排序时,最差情况下时间复杂度为0(N3/2);其平均时间复杂度尚无定论,猜想结果为0(N5/4)。
经验表明.希尔排序对规模以万计的待排序列会体现出比较好的效率。
此外,和简单插人排序不同的是,希尔排序不是稳定的排序,选取不同增量进行排序时,可能导致数值相同的两个元素发生相对位置上的改变。