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)

  • 相关阅读:
    Hanoi塔
    采药
    进制转换(大数)
    Load Balancing with NGINX 负载均衡算法
    upstream模块实现反向代理的功能
    epoll
    在nginx启动后,如果我们要操作nginx,要怎么做呢 别增加无谓的上下文切换 异步非阻塞的方式来处理请求 worker的个数为cpu的核数 红黑树
    粘性会话 session affinity sticky session requests from the same client to be passed to the same server in a group of servers
    负载均衡 4层协议 7层协议
    A Secure Cookie Protocol 安全cookie协议 配置服务器Cookie
  • 原文地址:https://www.cnblogs.com/yysbolg/p/8573896.html
Copyright © 2011-2022 走看看