九大排序算法之希尔排序

插入排序—希尔排序(Shell`s Sort)

       希尔排序是第一个突破O(n^2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序

原理:

       先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。

算法详细描述:

先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:

  • 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
  • 按增量序列个数k,对序列进行k 趟排序;
  • 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

动图演示:

我们简单处理增量序列:增量序列d = {n/2 ,n/4, n/8 .....1} n为要排序数的个数。

       先将要排序的一组记录按某个增量d(n/2,n为要排序数的个数)分成若干组子序列,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。继续不断缩小增量直至为1,最后使用直接插入排序完成排序。

详细步骤举例分析如下:

选择增量gap = length/2,缩小增量继续以gap = gap/2的方式,这种增量选择我们可以用一个序列来表示,{n/2,(n/2)/2...1},称为增量序列。希尔排序的增量序列的选择与证明是个数学难题,我们选择的这个增量序列是比较常用的,也是希尔建议的增量,称为希尔增量,但其实这个增量序列不是最优的。此处我们做示例使用希尔增量,

原始数组 [84,83,88,87,61,50,70,60,80,99],初始增量gap = length/2 = 5,整个数组分为五组如下

[84,50]、[83,70]、[88,60]、[87,80]、[61,99]

对于五组分别进行直接插入排序,五组结果为 [50,84]、[70,83]、[60,88]、[80,87]、[61,99],此时的数数组排序如下,

[50,70,60,80,61,84,83,88,87,99]

然后缩小变量gap = 5/2 =2,数组被分为两组[50,60,61,83,87]、[70,80,84,88,99]

对于两组分别进行直接插入排序,两组结果为[50,60,61,83,87]、[70,80,84,88,99],此时的数数组排序如下,

[50,70,60,80,61,84,83,88,87,99]

然后缩小变量gap = 2/2 =1,数组被分为一组[50,70,60,80,61,84,83,88,87,99]

此时,仅仅需要对以上数组简单微调,无需大量移动操作即可完成整个数组的排序,排序后的数组如下,

[50,60,61,70,80,83,84,87,88,99]

代码实现:

def shellSort(arr):
    n = len(arr)
    gap = n // 2
    while gap > 0:
        for i in range(gap, n):
            while i >= gap and arr[i] < arr[i - gap]:
                arr[i], arr[i - gap] = arr[i - gap], arr[i]
                i -= gap
        gap //= 2
    return arr

时间复杂度、时间复杂度及稳定性:

时间复杂度:最坏情况(数组逆序)为O(n^2),最好情况(数组顺序)为O(n^1.5)

空间复杂度:线性空间O(1)

稳定性:由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相                             同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。

猜你喜欢

转载自blog.csdn.net/qq_30123335/article/details/83210872