图解十大排序篇三---希尔排序

92 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

图解十大排序

3.1 前文回顾

在前俩篇文章中,给大家介绍了一下时间复杂度为O( n2 )的排序方法,大家还记得它们是哪几种排序吗?让我们回顾一下

冒泡排序

选择排序

插入排序

那还有时间复杂度比O( n2 )更低的排序算法吗?今天就让我们来介绍一下

3.2希尔排序

希尔排序是一种插入排序(如果大家忘记插入排序的话可以回去看上一篇文章),它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一。大家想一想,在什么情况下,插入排序的工作量会比较小呢?

  • 当数组元素较少的时候,插入排序的工作量会 比较小。因为插入排序的时间复杂度是O(n 2),工作量和n 2成正比,如 果n比较小,那么排序的工作量自然会小得多。
  • 当数组大部分元素有序的时候,插入排序的工作量也会相对 较小。因为在这种情况下,数组中的元素并不需要进行频繁的比较和 交换。

让我们来看一个例子 给定无序数组 : [3, 5, 2, 6, 4, 8]

比特截图2022-05-09-19-58-31.png

先让元素俩俩分组,每俩个元素之间的距离是数组总长度 n的一半,所以分组跨度是3

比特截图2022-06-01-22-25-25.png

如图所示:元素3和6一组,元素5和4一组,元素2和8一组,一共3组
我们对每一组元素进行插入排序,由于每一组元素的数量只有俩个,所以插入排序的效率就非常高,排序结果如下

比特截图2022-06-01-22-30-39.png

这样操作,让我们用尽可能少的操作,使数组整体的有序程度得到了显著提高,这样操作过后,我们可以进一步缩小分组跨度,重复上述工 作。把跨度缩小为原先的一半,就是跨度为1,进行重新分组,在本例中再次分组的话也就是跨度为1,直接进行插入排序

比特截图2022-06-01-22-38-00.png 这就是希尔排序,是希尔(Donald Shell) 于1959年提出的一种排序算法。上面示例中所使用的分组跨度(3,1),被称为希尔排序的增 量,增量的选择可以有很多种。我们在示例中所用的逐步折半的增量 方法,是Donald Shell在发明希尔排序时提出的一种朴素方法,被称 为希尔增量。

希尔排序的代码实现


public static void shellSort(int [] array) {
    int d = array.length; //俩元素之间的距离
    //折半,直到增量为1
    while (d > 1) {
        d = d >> 1;
        for (int x = 0; x < d; x++) {
            for (int i = x + d; i < array.length; i = i + d) {
                int t = array[i];
                int j;
                for (j = i - d; (j >= 0) && (array[j] > t); j = j - d) {
                    array[j + d] = array[j];
                }
                array[j + d] = t; //由于for循环之后还减少了d所以这里加回来
            }
        }
    }
}

public static void main(String[] args) {
    int [] array = {3, 4, 2, 6, 5, 8};
    shellSort(array);
    System.out.println(Arrays.toString(array));
}

算法分析

  • 最佳情况:T(n) = O(nlog2 n)
  • 最坏情况:T(n) = O(nlog2 n)
  • 平均情况:T(n) =O(nlog2n)

下篇预告: 图解十大排序篇四 归并排序