【算法】希尔排序及其Python实现

希尔排序思想

有点类似归并可以分为两步:
(1)拆分; (2) 排序。并且不断重复这两个步骤。

  1. 拆分:gap将数据拆成一个个小的逻辑小组,并且gap不断减少。一开始每个组最多只有2个元素,最后慢慢变成整体数据的一半,然后变成整体。而gap从一开始的int(len/2)最后变为2.
  2. 排序:对每个小组进行插入排序。

思路形象记忆:
其实就升级版插入排序,插入排序适用于小规模或基本有序,希尔排序融入分治的思想,用一个个小的插入排序去解决大规模、无序的问题。

代码实现要注意的地方
  1. 考虑极端情况;
  2. gap要记得int一下;
  3. 只要j小于gap,说明还可以向左走,所以j>=gap
  4. 只要arr[j-gap]>tmp,说明需要向左走;
  5. 不是排完一个逻辑分组才去排另外一个,而是同时的。每一组每组都优化一个数;
  6. 特点:其实就是在插入排序上多一个while循环判断gap。三个循环都与gap有关。
    while gap>0判断gap是否需要继续减半。
    for i in range(gap, arr_len)相当于选中插入排序时,准备插队的那个未排序数,而且这个i的特点是,轮流指向不同的逻辑分组,例如假设长度为8,gap=2时,此时有两个逻辑分组,i会分别取2,3,4,5,6,7。当i=2,4,6时,其实是对第一个逻辑分组进行插入排序(位置0即为第一个逻辑分组中默认已排序的初始值);当i=3,5,7时,其实是对第一个逻辑分组进行插入排序(位置1即为第二个逻辑分组中默认已排序的初始值)。
    while j>=gap and arr[j-gap]>tmp就是插入排序。j的判断值其实就是下面arr[j] = arr[j-gap]中后面的变量arr[j-gap]索引大于等于0的条件,即j-gap>=0,故j>=gap。(在插入排序中为j>=0,因为插入排序中赋值的时候是arr[j+1] = arr[j],其实本质是一样的。插入排序代码)
代码
def shell_sort(arr):

    # 排序初始值
    arr_len = len(arr)
    gap = int(arr_len/2)

    # 特殊情况考虑
    if arr_len==0:
        return None
    if arr_len==1:
        return arr

    # 只要增量未减为0,则继续
    while gap>0:
        for i in range(gap, arr_len):
            tmp = arr[i]
            j=i
            # 单组插入排序
            # 只要j小于gap,说明还可以向左走
            # 只要arr[j-gap]>tmp,说明需要向左走
            while j>=gap and arr[j-gap]>tmp:
                # 比tmp大的值右移
                arr[j] = arr[j-gap]
                # j减少增量值
                j -= gap
            # 若找到最佳位置,则插入
            # 因为一旦j大于gap则说明已经是最左边的数了,所以最佳位置就是j
            arr[j] = tmp
        # 每个逻辑分组都排序后,gap减半
        gap = int(gap/2)

    return arr

arr = [3,2,1,5,6,5]
shell_sort(arr)
print(arr)

参考:希尔排序–简单易懂图解

你可能感兴趣的:(Python,算法)