zoukankan      html  css  js  c++  java
  • 排序算法(3)--Insert Sorting--插入排序[3]--Shell Sort--希尔排序

    1.基本思想

      希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

    2.实现原理

      对于n个待排序的数列,取一个小于n的整数gap(gap被称为步长)将待排序元素分成若干个组子序列,所有距离为gap的倍数的记录放在同一个组中;然后,对各组内的元素进行直接插入排序。 这一趟排序完成之后,每一个组的元素都是有序的。然后减小gap的值,并重复执行上述的分组和排序。重复这样的操作,当gap=1时,整个数列就是有序的。

    3.代码实例

    (1)代码:

       /**
         * 对希尔排序中的单个组进行排序
         * <p>
         * 参数说明:
         * a -- 待排序的数组
         * n -- 数组总的长度
         * i -- 组的起始位置
         * gap -- 组的步长
         * <p>
         * 组是"从i开始,将相隔gap长度的数都取出"所组成的!
         */
        public static void groupSort(int[] a, int n, int i, int gap) {
            //打印分组
            System.out.print("gap="+gap+" [");
            //打印第一个比较的元素
            System.out.print(a[i]);
            //直接插入排序
            for (int j = i + gap; j < n; j += gap) {
                //被比较的元素
                System.out.print(" "+a[j]);
                // 如果a[j] < a[j-gap],则寻找a[j]位置,并将后面数据的位置都后移。
                if (a[j] < a[j - gap]) {
                    int tmp = a[j];
                    int k = j - gap;
                    while (k >= 0 && a[k] > tmp) {
                        a[k + gap] = a[k];
                        k -= gap;
                    }
                    a[k + gap] = tmp;
    //                System.out.print(" ("+a[j]+"<-->"+a[j-gap]+")");
                }
            }
            System.out.println("]");
        }
        /**
         * 希尔排序
         * <p>
         * 参数说明:
         * a -- 待排序的数组
         * n -- 数组的长度
         */
        public static void shellSort(int[] a, int n) {
            // gap为步长,每次减为原来的一半。
            for (int gap = n / 2; gap > 0; gap /= 2) {
                // 共gap个组,对每一组都执行直接插入排序
                for (int i = 0; i < gap; i++)
                    groupSort(a, n, i, gap);
                System.out.printf("after sort:");
                for (int i = 0; i < a.length; i++)
                    System.out.printf("%d ", a[i]);
                System.out.println();
                System.out.println();
            }
        }
        public static void main(String[] args) {
            int i;
            int a[] = {80, 30, 60, 40, 20, 10, 50, 70,100};
            System.out.printf("before sort:");
            for (i = 0; i < a.length; i++)
                System.out.printf("%d ", a[i]);
            System.out.println();
            System.out.println();
            shellSort(a, a.length);
        }

    (2)结果:

    before sort:80 30 60 40 20 10 50 70 100

    gap=4 [80 20 100]

    gap=4 [30 10]

    gap=4 [60 50]

    gap=4 [40 70]

    after sort:20 10 50 40 80 30 60 70 100

    gap=2 [20 50 80 60 100]

    gap=2 [10 40 30 70]

    after sort:20 10 50 30 60 40 80 70 100

    gap=1 [20 10 50 30 60 40 80 70 100]

    after sort:10 20 30 40 50 60 70 80 100

    4.算法分析

    (1)希尔排序时间复杂度

      希尔排序的时间复杂度与增量(即,步长gap)的选取有关。例如,当增量为1时,希尔排序退化成了直接插入排序,此时的时间复杂度为O(N²),而Hibbard增量的希尔排序的时间复杂度为O(N3/2)。

    (2)希尔排序空间复杂度

      空间复杂度是O(1) 因为只有一个缓冲单元。

    (3)希尔排序稳定性

      希尔排序是不稳定的算法,它满足稳定算法的定义。对于相同的两个数,可能由于分在不同的组中而导致它们的顺序发生变化。

      算法稳定性 -- 假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!

    5.排序特点

      我们知道一次插入排序是稳定的,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以希尔排序是不稳定的。

      希尔排序的时间性能优于直接插入排序,原因如下:

      (1)当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。

      (2)当n值较小时,n和n2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(n2)差别不大。

      (3)在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。

      因此,希尔排序在效率上较直接插人排序有较大的改进。

     希尔排序的平均时间复杂度为O(nlogn)

  • 相关阅读:
    WPF 自定义ComboBox样式,自定义多选控件
    .net core 的网站
    grpc详细入门
    如何遍历所有程序集中的成员、类
    【C#】IDispose接口的应用
    redis集群简介
    What’s your most controversial programming opinion?
    初学PHP——欲得生受用,须下死功夫!
    Great OOP
    博客园背景特效粒子鼠标跟踪吸附
  • 原文地址:https://www.cnblogs.com/yysbolg/p/8573896.html
Copyright © 2011-2022 走看看