排序算法(三) —— 希尔排序(Shell Sort)、归并排序(Merge Sort)

参考:https://www.cnblogs.com/onepixel/articles/7674659.html

希尔排序(Shell Sort)

时间复杂度(平均): O(n^log2n)  时间复杂度(最坏): O(n^2)  时间复杂度(最好):O(n)   空间复杂度:O(1)  稳定性:不稳定

 

算法描述

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

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

代码

'''
希尔排序
算法原理:分组,span = len(nums)/2 (可以理解为组数),依次对每组中元素(跨度为span)插入排序; 然后span/2 重复上述排序
跨度为span的一组一组元素为排序结果 (因为采用了跨度,保证了插入排序的平均复杂度较小,从而降低希尔排序的时间复杂度)
'''

def sort(nums):
    span = int(len(nums)/2)
    while span > 0:
        for i in range(span, len(nums), 1):
            temp = nums[i]
            j = i
            while temp < nums[j -span] and j - span > -1:
                nums[j] = nums[j - span]
                j = j - span
            nums[j] = temp
        span = int(span/2)

def sort1(nums):
    # 按分组去算,比较繁琐,且比较绕
    if len(nums)==1:
        return nums
    span = int(len(nums)/2)  # 分组个数
    while span > 0:
        n = int(len(nums)/span) # 组内数
        for i in range(span + 1):
            for j in range(1, n, 1):
                if (j * span + i) > len(nums) - 1:
                    break
                for k in range(j-1, -1, -1):
                    if nums[k * span + i] > nums[j * span + i]:
                        temp = nums[k * span + i]
                        nums[k * span + i] = nums[j * span + i]
                        nums[j * span + i] = temp
        span = int(span/2)

 

归并排序(Merge Sort)

时间复杂度(平均): O(nlog2n)  时间复杂度(最坏):O(nlog2n)   时间复杂度(最好):O(nlog2n)    空间复杂度:O(n)  稳定性:稳定

 

算法描述

  • 把长度为n的输入序列分成两个长度为n/2的子序列;
  • 对这两个子序列分别采用归并排序;
  • 将两个排序好的子序列合并成一个最终的排序序列。

代码

'''
归并排序
采用递归的方法, 长度小于一的数组,直接返回;长度为二的数组,两者比较返回;长度大于三,切分左右两部分,分别递归调用归并排序算法,得到排好序的左边数组和右边数组,然后遍历两个数组,进行排序。
分块为排序好的数组
'''
def merge_sort(nums):
    if len(nums)<=1:
        return nums
    if len(nums)==2:
        if nums[0] > nums[1]:
            temp = nums[0]
            nums[0] = nums[1]
            nums[1] = temp
        return nums
    half = int((len(nums) + 1)/2)
    left = merge_sort(nums[:half])
    right = merge_sort(nums[half:])
    res = []
    i, j = 0, 0
    # while i < len(left) or j < len(right):
    #     if i == len(left):  # 这里每次需要再判断,实际上如果知道剩余的是right或者left,之后直接加入到res即可,不需要再判断
    #         res.append(right[j])
    #         j += 1
    #     elif j == len(right):
    #         res.append(left[i])
    #         i += 1
    #     elif left[i] <= right[j]:
    #         res.append(left[i])
    #         i += 1
    #     else:
    #         res.append(right[j])
    #         j += 1

    while i < len(left) and j < len(right): # 这种逻辑也可以直接判断 if j == len(right): res += left[i:]   if i == len(left): res += left[j:]
        if left[i] <= right[j]:
            res.append(left[i])
            i += 1
        else:
            res.append(right[j])
            j += 1
    while i < len(left):
        res.append(left[i])
        i += 1
    while j < len(right):
        res.append(right[j])
        j += 1

    return res

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微知girl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值