数据结构之希尔排序(五)

排序思路:我们设置一个步长,然后我们根据这个步长进行划分子序列,得到子序列1,子序列2….,然后我们对每个子序列进行直接插入排序,我们也知道当整个数列基本有序的时候使用直接插入排序的效率是非常高的。然后我们缩小步长,则我们划分的子序列的个数越来越少,我们每个子序列中的数据越来越多,则我们基本有序的数据就越来越多,直到我们的增量为1时,我们对整个已经基本有序的序列采用一次直接插入排序,则我们的排序结束。
这里写图片描述

直接实现:

private static void shellsort(int[] arr, int length) {
        // 初始设置增量为数组长度的一半,则我们的每个子序列只有两个数据
        // 我们每次的排序都是根据步长来确定的,而我们的步长每次排序完成后都要改变,直到步长为1,我们这里采用的步长长度每次为一半
        // 在上面设置了步长以后,则我们的待排序数组已经被分成若干个子序列了,则我们对每个子序列进行直接插入排序
        for (int gap = length / 2; gap >= 1; gap = gap / 2) { 
            int m;
            // 我们在这里设置一个循环,这个循环我们用于对每个子序列的起点进行设置,每个子序列的起点都是在0到gap之间的
            // 这样我们就可以把子序列抽离出来,分别是m,m+gap,m+gap+gap...,则我们对这个序列进行直接插入排序
            for (m = 0; m < gap; m++) { 
                int i;
                int temp;
                for (i = m + gap; i < length; i = i + gap) { // 我们对这个序列进行直接插入排序
                    int j = i; // 在这里我们单独定义一个j出来,不能直接对i进行操作,直接操作i以后,i会发生变化,则我们的遍历对象不准确了
                    while (j != m) {
                        if (arr[j] <= arr[j - gap]) { // 这个子序列相邻元素之间的距离不再是1,而是gap
                            temp = arr[j - gap];
                            arr[j - gap] = arr[j];
                            arr[j] = temp;
                        }
                        j = j - gap; // 下标跳转到下一个元素
                    }
                }
            }
        }

        for (int i = 0; i < 15; i++) {
            System.err.printf("%d ", arr[i]);
        }
    }

算法分析: 希尔排序原理:设置间隔变量,将数组进行分组,组内排序,然后缩小间隔变量,直至间隔变量为1(结束条件)
1. 希尔排序的空间占用率为O(1),
2. 希尔排序在平均情况下时间复杂度为O(nlogn),最好情况下为O(n的平方)
下面来分析原始的希尔排序的时间复杂度,初始步长d=n/2,下一次步长d=d/2
第一次比较次数,每组2个元素:1*n/2
第二次比较次数,每组4个元素:最坏(1+2+3)*n/4
第三次比较次数,每组8个元素:最坏(1+2+3+……+7)*n/8
2^(m-1) ( m 表示第几次比较 ) < 每组最坏的元素比较次数 < 2^(m)
例子 :2^2 < 7 < 2^3 (第 3 次比较,最后一个元素的最差比较次数 )
累加求极限,得到算法复杂度小于 O(n^2) 。
3.希尔排序是一种不稳定的内部排序算法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章