zoukankan      html  css  js  c++  java
  • 数据结构(四十六)插入排序(1.直接插入排序(O(n²)) 2.希尔排序(O(n3/2)))

      一、插入排序的基本思想

      从初始有序的子集合开始,不断地把新的数据元素插入到已排列有序子集合的合适位置上,使子集合中数据元素的个数不断增多,当子集合等于集合时,插入排序算法结束。常用的 插入排序算法有直接插入排序和希尔排序两种。

      

      二、直接插入排序

      1.直接插入排序的定义

      直接插入排序的基本思想是:顺序地把待排序的数据元素按其值的大小插入到已排序数据元素子集合的适当位置。子集合的数据元素个数从只有一个数据元素开始逐次增大。当子集合大小最终和集合大小相同时排序完毕。

      2.直接插入排序的实现

        public static void straightInsertionSort(int[] L) {
            int i, j, temp;
            for (i = 0; i < L.length - 1; i++) {    
                temp = L[i+1];                        // 保存要插入的数据元素
                j = i;                                
                while (j > -1 && temp <= L[j]) {    // 将temp插入到原数组集合中
                    L[j+1] = L[j];
                    j--;
                }
                L[j+1] = temp;                         
            }
        }

      int[] array1 = {9,1,5,8,3,7,4,6,2};
      初始时,子集合中L0已经排好序,即为{9}
      i=0时,temp=L1=1,j=0,0大于-1且1小于9,则L1=9,j=-1,L0=1,即将1插入到9的前面,集合中{1,9}
      i=1时,temp=L2=5,j=1,1大于-1且5小于9,则L2=9,j=0,0大于-1但5不小于1,则L1=5,集合中{1,5,9}
      i=2时,temp=L3=8,即将8和9比较,8插入到9的前面,8和5比较,不动,8和1比较,也不动,集合中{1,5,8,9}
      ...

      3.直接插入排序的性能分析

      (1)时间复杂度为O(n²)

    • 最好情况是原始数据集合已经全部排好序。这时内层while循环的循环次数每次均为0,外层for循环中每次数据元素的比较次数均为1,数据元素的赋值语句执行次数均为2。因此整个排序过程中比较次数为n-1,移动次数为2(n-1),此时的时间复杂度为O(n)。
    • 最坏情况是与原始数据集合反序排列。这时内层while循环的循环次数每次均为i,这样,整个外层for循环中的比较次数为(1+1)+(2+1)+...+(n-1+1)=(n-1)(n+2)/2,而移动次数为(1+2)+(2+2)+...+(n-1+2)=(n-1)(n+4)/2。此时的时间复杂度为O(n²)。  
    • 随机情况是数据集合中大小的排列是随机的。这时比较次数的期望和移动次数的期望均为n²/4,此时的时间复杂度为O(n²)。

      (2)空间复杂度为O(1)。

      (3)是一种稳定的排序算法。

      三、希尔排序

      1.希尔排序的定义

      希尔排序的基本思想是:把待排序的数据元素分成若干个小组,对同一小组内的数据元素用直接插入法排序;小组的个数逐次缩小;当完成了所有数据元素都在一个组内的排序后排序过程结束。希尔排序又称作缩小增量排序。

      在直接插入排序算法的性能分析中可以得出结论:原始数据集合越接近有序,直接插入排序算法的时间效率越高,其时间效率在O(n)~O(n²)之间。这个结论是希尔排序算法能够成立的基础。希尔排序算法把待排序数据元素分成若干小组,在小组内用直接插入排序算法排序,当把若干个小组合并为一个小组时,组中的数据元素集合将会接近有序,这样各组内的直接插入排序算法的时间效率就很好,最终整个希尔排序的时间效率就很高。

      2.希尔排序的实现

        public static void shellSort(int[] L, int[] d) {
            int i, j, k, m, span;
            int temp;
            for (m= 0; m < d.length; m++) {
                span = d[m];
                for (k = 0; k < span; k++) {
                    /********将i=0换成i=k,1换成span的直接插入排序**********/
                    for (i = k; i < L.length - span; i = i + span) { 
                        temp = L[i+span];
                        j = i;
                        while (j > -1 && temp <= L[j]) {
                            L[j + span] = L[j];
                            j = j - span;
                        }
                        L[j + span] = temp;
                        print(L);
                    }
                    /***********************************************/
                }
                System.out.print("span的值为" + span + "时得到的序列为: ");
                print(L);
            }
        }

      分析代码执行过程与输出为:

    int[] array1 = {9,1,5,8,3,7,4,6,2};int[] d = {4,2,1};
    分析执行过程:
    m=0时,span=4,k=0时,i=0,j=0时,交换9和3得到{3,1,5,8,9,7,4,6,2};i=4,j=4时,交换9和2得到{3,1,5,8,2,7,4,6,9};j=0时,交换3和2得到{2,1,5,8,3,7,4,6,9};排序{2,3,9}
    m=0时,span=4,k=1时,i=1,1和7不交换,排序{1,7}
    m=0时,span=4,k=2时,i=2,交换5和4,得到{2,1,4,8,3,7,5,6,9};排序{4,5}
    m=0时,span=4,k=3时,i=3,交换8和6,得到{2,1,4,6,3,7,5,8,9};排序{6,8}
    m=0结束,得到{2,1,4,6,3,7,5,8,9};可以发现数字1、2等小数字已经在前两位,而8、9等大数字已经在后两位,整个序列已经基本有序了。

    m=1时,span=2,k=0时,排序{2,4,3,5,9}为{2,3,4,5,9}
    m=1时,span=2,k=1时,排序{1,6,7,8}
    m=1结束,交叉两个排序得到{2,1,3,6,4,7,5,8,9}即将之前5个和4个分别直接插入排序,然后插入到原来的位置
    m=2时,span=1,k=0时,排序{2,1,3,6,4,7,5,8,9}得到{1,2,3,4,5,6,7,8,9}
    输出为: 希尔排序前:
    9 1 5 8 3 7 4 6 2 span的值为4时得到的序列为: 2 1 4 6 3 7 5 8 9 span的值为2时得到的序列为: 2 1 3 6 4 7 5 8 9 span的值为1时得到的序列为: 1 2 3 4 5 6 7 8 9 希尔排序后: 1 2 3 4 5 6 7 8 9

      3.希尔排序的性能分析

      (1)时间复杂度

      希尔排序增量序列的选取非常关键,需要注意的是增量序列的最后一个增量值必须是1才行。通过设置合适的增量序列,可以使得时间复杂度为O(n3/2),要好于直接插入排序的O(n²)。

      (2)空间复杂度

      希尔排序算法的空间复杂度为O(1)。

      (3)稳定性

      由于希尔排序算法是按增量分组进行的排序,两个相同的数据元素有可能分在不同的组中,所以希尔排序算法是一种不稳定的排序算法。

      

  • 相关阅读:
    解题报告:luogu P1156
    解题报告:AT3605
    矩阵乘法与斐波那契数列
    九、模块
    八、异常
    七、文件处理
    六、对象和内存分析
    五、函数和内存分析
    四、控制语句
    三、序列
  • 原文地址:https://www.cnblogs.com/BigJunOba/p/9298172.html
Copyright © 2011-2022 走看看