数据结构与算法--希尔排序

简介

希尔排序是插入排序的一种,又称“缩小增量排序”,是插入排序算法的一种更高效的改进版本


排序图解

从图中可以看出每一趟排序中都分成 gap 组,每组都有 gap + 1 个元素,对每一组中的 arr[j] 和 arr[j - gap] 进行比较,如果 arr[j] < arr[j - gap] 则相互交换值

gap 初始值为原数组长度的一半,随后在其他趟次排序中 gap 值变为原来的一半,直到 gap 的值变为 0 后,数组中的元素变得有序  


排序原理

  1. 选定一个增长量h,按照增长量h作为数据分组的依据,对数据进行分组

  2. 对分好组的每一组数据完成插入排序

  3. 减小增长量,最小减为1,重复第二步操作,直到增长量为0


代码实现

交换法

public void shellSort(int[] arr){
    int gap = arr.length / 2;
    while (gap > 0) {
        for (int i = gap; i < arr.length; i++) {
            //遍历各组中所有的元素(共gap组,每组有gap+1个元素),步长为gap
            for (int j = i - gap; j >= 0; j -= gap) {
                //如果当前元素大于加上步长gap后的那个元素,则交换值
                if (arr[j] > arr[j + gap]){
                    exchange(arr,j,j + gap);
                }
            }
        }

        //增量gap逐步进行缩小
        gap = gap / 2;
    }
}

public void exchange(int[] arr, int j, int i) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

移位法

public void shellSort2(int[] arr){
    int gap = arr.length / 2;
    while (gap > 0) {
        //从第gap个元素,逐个对其所在的组进行直接插入排序
        for (int i = gap; i < arr.length; i++) {
            int j = i;
            int temp = arr[j];
            if (arr[j] < arr[j - gap]){
                
                while (j - gap >= 0 && temp < arr[j - gap]){
                    //移动
                    arr[j] = arr[j - gap];
                    j -= gap;
                }
                
                //当退出while循环后,就给temp找到了插入的位置
                arr[j] = temp;
            }
        }

        //增量gap逐步进行缩小
        gap = gap / 2;
    }
}

public void exchange(int[] arr, int j, int i) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

时间复杂度分析

通过测试发现,在处理大批量数据时,希尔排序的性能确实高于插入排序

  • 最优时间复杂度:根据步长序列的不同而不同

  • 最坏时间复杂度:O(N2)


算法稳定性

对于相同的两个数,可能由于分在不同的组中而导致它们的顺序发生变化。如图解中的两个5,在排完序后两者的位置发生了变化。所以希尔排序是不稳定的

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

posted @ 2022-07-26 00:08  伊文小哥  阅读(116)  评论(0编辑  收藏  举报