四 希尔排序

    科技2022-09-02  90

    此博客用于个人学习,来源于算法的书籍和网上的资料,对知识点进行一个整理。

    1. 概述:

    希尔排序是一种基于插入排序的快速的排序算法,对于大规模乱序数组插入排序很慢,因为它之后交换相邻的元素,因此元素只能一点一点地从数组的一端移动到另外一端。希尔排序为了加快速度简单地改进了插入排序,交换不相邻的元素对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。

    2. 算法:

    希尔排序的思想是使数组中任意间隔为 h 的元素都是有序的,这样的数组被称为 h 有序数组。在进行排序的时候,如果 h 很大,我们就能将元素移动到很远的地方,为实现更好的 h 有序创造方便。我们这里使用的是 N/3 开始递减到 1 的递增序列。sort 方法的大体逻辑与插入排序相同,但在外面加入一层 while 循环,循环变量 h 每次除以三,与前面对应。

    3. 代码实现:

    /** * 希尔排序 */ public class Shell { public static void sort(Comparable[] a){ int h = 1; while (h < a.length/3){ h = h*3 + 1; } while (h >= 1){ for (int i = 0;i < a.length;i ++){ //将a[j]插入到a[j-h],a[j-2h],a[j-3h]...中去 for (int j = i;j > 0 && less(a[j],a[j-h]);j -= h){ exchange(a,j,j-h); } } h /= 3; } } private static boolean less(Comparable v,Comparable w){ return v.compareTo(w) < 0; } private static void exchange(Comparable[] a,int i,int j){ Comparable t = a[i]; a[i] = a[j]; a[j] = t; } private static void show(Comparable[] a){ //在单行中打印数组 for (int i = 0;i < a.length;i++){ System.out.println(a[i]+" "); } System.out.println(); } /** * 测试数组元素是否有序 * @param a * @return */ public static boolean isSorted(Comparable[] a){ for (int i = 1;i < a.length;i++){ if (less(a[i],a[i-1])){ return false; } } return true; } }

    4. 特点:

    希尔排序是一种在实际应用中都十分常见的算法,因为对于中等大小的数组它的运行时间是可以接受的,它的代码量很小,而且不需要使用额外的内存空间。更加高效的算法确实也有,但他们可能只会比希尔排序快两倍(甚至可能还不到),而且更加复杂。如果你需要解决一个排序问题而又没有系统排序函数可以用,可以先用希尔排序,然后再考虑是否值得将它替换成更加复杂的排序算法。

    5. 算法分析:

    时间复杂度:希尔排序的复杂度和增量序列是相关的,但在最坏情况下(数组逆序),复杂度为 O(n^2)。空间复杂度:只是用了2个循环变量以及1到2个标志和交换等的中间变量,这个与待排序的记录个数无关,空间复杂度为 O(1)。稳定性:不稳定的,虽然插入排序是稳定的,但是希尔排序在插入的时候是跳跃性插入的,有可能破坏稳定性。例如 7 5 5 8,当 i = 2时,分成两组 [7 5],[5 8]。分别使用插入排序后,第一组为 [5 7],第二组为 [5 8]。 合并后可以发现,两个 5(相同元素)的相对位置发生了改变。
    Processed: 0.012, SQL: 9