📜  壳排序(1)

📅  最后修改于: 2023-12-03 14:51:38.649000             🧑  作者: Mango

壳排序(Shell Sort)

壳排序是对插入排序的一种改进,也称为“缩小增量排序”。与插入排序不同的是,壳排序允许元素跳跃移动,以换取比插入排序更少的比较次数。

思路

壳排序的思路是“先大后小再插入排序”,我们先将整个待排序数组按照一定的增量划分为若干个子序列,分别进行插入排序;然后逐步缩小增量,直到增量为 1 ,最后使用插入排序将整个序列排序完毕。

具体流程如下:

  1. 定义一个增量序列D,增量序列的最后一个数必须是1;
  2. 针对每个增量,将数组划分为若干个长度为此增量的子序列,对子序列分别进行插入排序;
  3. 增量不断缩小,重复操作2直至增量为1,最后对整个序列进行一次插入排序。

步骤2中,对于每个子序列,我们采用插入排序进行排序。因为每个子序列的长度相对较短,插入排序的精髓就是在少量元素时的高效率,所以采用插入排序是非常合理的。

步骤2和步骤3,由于增量序列的缘故,保证了前一个步骤得来的有序序列在下一个步骤中仍然是有序的,所以本质上是在对已经排好序的序列进行再次排序。

代码实现

壳排序的代码实现分为两部分:生成增量序列和排序实现。

增量序列生成

增量序列的生成方法并没有什么固定的规定,可以自由选择一种方法。一般来说,增量序列只要保证最后一个数是1即可。

以下是一种增量序列的生成方法:

def shell_sort_gap(len):
    gap = []
    i = 1
    while i <= len:
        gap.append(i)
        i = i * 3 + 1
    gap = gap[::-1]
    return gap

在这个方法中,我们采用递增序列。首先设定一个数 1,然后用一个 while 循环不断将 1 乘以一个大于 1 的数,每次得到的结果加到增量序列中,直到当前的增量大于数组的长度为止。

在代码中,gap[::-1]是将生成的增量序列翻转,就是将最后一个数 1 放到了序列的最前面。

排序实现

我们使用 Python 实现壳排序的排序实现:

def shell_sort(arr):
    n = len(arr)
    gap = shell_sort_gap(n)
    for gap_val in gap:
        for i in range(gap_val, n):
            temp = arr[i]
            j = i - gap_val
            while j >= 0 and arr[j] > temp:
                arr[j + gap_val] = arr[j]
                j -= gap_val
            arr[j + gap_val] = temp
    return arr

在这个实现中,我们先获取了增量序列,然后按照增量序列中的每个值循环进行排序。

在当前的增量之下,我们按照插入排序的思路,将每个子序列中的元素进行排序。因为增量序列是递增的,所以每次排序得到的子序列都是有序的,且已经排好序的元素均不会被打乱,所以可以保证后面的排序都是在有序序列中进行的。

性能分析

壳排序的时间复杂度和增量序列的设置有关,最差情况下为 O(n^2)。但一般情况下壳排序的时间复杂度在 O(n^1.3) 左右,比插入排序的 O(n^2) 要优秀很多。

壳排序是一种内层循环使用插入排序的排序算法,所以空间复杂度为 O(1)。

总结

壳排序在大数据随机排序的情况下,效率较高,但是也有一些性能瓶颈。因此,如果排序场景有特殊要求,需要根据实际情况选择合适的排序算法。