减治算法: 插入排序和希尔排序(详解)

来源:互联网 发布:互联网平台运营知乎 编辑:程序博客网 时间:2024/06/05 10:45

减治法:

减治(decrease-and-conquer)法利用了一个问题给定实例的解和同样问题较小实例的解之间的某种关系解决问题。我们既可以自顶向下(导致递归),也可以自底向上(导致迭代)地运用该关系解决问题。

插入排序:

想象一下整理扑克牌的情景,我们将每一张牌插入到其他已经有序的牌中的适当位置。在数组中,为了给要插入的元素腾出空间,我们需要将其余所有元素在插入之前都向右移动一位,这种算法叫做插入排序
插入排序所需的时间取决于输入中元素的初始顺序。对一个很大的基本有序的数组进行插入排序会比对一个随机顺序的数组进行插入排序快得多。

    public static void insertion(Integer[] r) {        int N = r.length;        int j;        for (int i = 1; i < N; i++) {            int p = r[i];            for (j = i; j > 0 && r[j - 1] > p; j--)                r[j] = r[j - 1];// 将正确位置之后的元素都向后移动一格。            r[j] = p;//将第i个元素插入到已经有序的数组        }    }

算法分析:
插入排序的基本操作是比较,比较次数显然依赖于特定的输入。在最坏情况下比较次数和插入排序相同,大约为(N^2)/2。最好的情况下是N-1次,不过这没特别大的意义,对我们比较重要的是对随机序列的数组排序的性能。对随机数组,插入排序的平均比较次数是最坏情况下的一半,大约为(N^2)/4

改良分析:
插入排序性能的瓶颈在于:每次都要移动索引位置到正确位置之间所有的元素,如果最小的元素在数组最右侧,那我们就需要移动整个数组。这显然是十分不划算的,所以有人发明了一个改进的算法,希尔排序(shellsort)。

希尔排序:

希尔排序是冲破二次时间屏障的第一批算法之一。不过直到它最初被发现的若干年后才证明了它的亚二次时间届。希尔排序使用一个序列h1,h2,……,ht, 叫做增量序列(increment sequence)。只要h1 = 1,任何增量序列都是可以的,不过有些序列比另外一些序列更好。

该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。

希尔排序

    public static void shell(Integer[] r) {        int N = r.length;        int h = 1;        while (h < N / 3)            h = 3 * h + 1;//计算增量序列的最大值:1,4,13,40,121,364,1093        while (h >= 1) {            for (int i = h; i < N; i++) {//i初始化h以避免数组越界                for (int j = i; j >= h && r[j] < r[j - h]; j -= h) {                    int temp = r[j];                    r[j] = r[j - h];                    r[j - h] = temp;                }            }            h /= 3;//取增量序列的前一个值        }    }

算法分析:
研究希尔排序的性能非常复杂,上述代码的最差情况的时间复杂度为O(N^3/2)
原始的算法实现(希尔增量)在最坏的情况下需要进行O(n^2)的比较和交换。V. Pratt的书对算法进行了少量修改,可以使得性能提升至O(n log^2 n)。这比最好的比较算法的O(n log n)要差一些。

增量序列:
增量序列的选择是希尔排序的一个重要部分。只要最终步长为1任何步长序列都可以工作。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。
希尔排序的增量序列


总结:

插入排序:平均性能比最差情况下快一倍,以及对基本有序数组的优异表现,使得插入排序优于选择排序和冒泡排序。

希尔排序:希尔排序的性能在实践中是完全可以接受的,编程简单的特点使他领先于很多其他的排序算法,并且它不需要额外的内存空间

1 0
原创粉丝点击