十大排序、七大查找算法python实现——希尔排序(shell sort)

十大排序、七大查找算法python实现——希尔排序(shell sort)

原理参考链接:https://www.cnblogs.com/onepixel/articles/7674659.html

希尔排序的原理是,通过设定步长序列,将无序数组划分成不同的子数组,然后分别对子数组进行插入排序,随着步长的不断缩小,数组也逐渐变成有序。具体步骤如下:

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

    gap = n // 2  # 初始步长
    while gap > 0:  # 最后一次步长为1(即普通的插入排序),然后整个希尔排序结束

        # 想像成,以步长 gap 将原始序列划分成 gap 个待排序的序列,对每个序列使用普通的插入排序进行排序
        # 序列1: [L[0], L[gap], L[2*gap]...]
        # 序列2: [L[1], L[1+gap], L[1 + 2*gap]...]
        # 序列3: [L[2], L[2+gap], L[2 + 2*gap]...]
        # 请查看插入排序算法 https://github.com/wangy8961/python3-algorithms/blob/master/4.%20%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F%20-%20Insertion%20Sort/3_best_insertion_sort_asc.py
        # 助记:普通的插入排序算法中步长是 1 ,把插入排序中的步长 1 替换为 gap
        for i in range(gap, n):  # "未排序序列" 的第1个元素分别是L[gap], L[1+gap], L[2+gap] ... ,所以变量 i 表示的下标是 gap, 1+gap, 2+gap ...
            temp = L[i]
            j = i
            # j >= gap是因为后续j[j-gap],否则下标越界
            while j >= gap and temp < L[j-gap]:
                L[j] = L[j-gap]
                j -= gap
            L[j] = temp
        print(L)
        gap = gap // 2  # 得到新的步长

如何理解上述代码呢? 

首先,我们需要设置步长序列,通过条件gap>0的while循环,不断让gap整除2,以得到{n/2,n/4,n/8,n/16,...1}的步长序列,对于每个步长序列,我们可以得到数量分别为n/2,n/4,...,1的子数组;

然后,使用直接插入排序的方法对这些子数组进行排序,如下述代码所示,这里就是对子数组进行插入排序,看过我的插入排序的小伙伴们一定知道,在这里不同的地方就在于将L[j-1]换成了L[j-gap],这是为什么呢?其实,我们可以将原数组划分成[L[0], L[1],L[2],...,L[gap-1], L[gap],L[gap+1],...,L[2*gap]],其中,如果这是执行第一遍的时候,L[2*gap]即是L[n],现在就显而易见了吧,在插入排序算法中,我们将第一个元素作为有序数组,从第二个元素开始进行与有序数组比较,而在子数组中j在区间[gap,n]中,也就是说L[j]即为第二个元素,L[j-gap]即为第一个元素,到此我们是不是很清楚的理解了希尔排序的执行过程了。

while j >= gap and temp < L[j-gap]:
    L[j] = L[j-gap]
    j -= gap
L[j] = temp

算法执行结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值