L7:排序-4(希尔、计数、桶、基数)

希尔排序(Shell Sort)

  • 是一种分组插入排序算法:
    • 首先取一个整数d1=n/2,将元素分为d1个组,每组相邻两个元素之间距离为d1,在各组内进行直接插入排序
    • 取第二个整数d2=d1/2,重复上述分组排序过程,直到di=1,即所有元素在同一组内进行直接插入排序
  • 希尔排序每趟并不使某些元素有序,而是使整体数据越来越接近有序;最后一趟排序使得所有数据有序
  • 排序速度:堆排序<希尔排序<快速排序
  • 时间复杂度比较复杂,和选取的gap序列有关

代码:

def insert_sort(li): #原始插入排序
    for i in range(1, len(li)): #表示摸到的牌的下标
        temp = li[i] #摸到的牌的值
        j = i - 1 #手里的牌的下标
        while j >= 0 and li[j] > temp:
            li[j+1] = li[j]
            j -= 1
        li[j+1] = temp

def insert_sort_gap(li, gap): #有gap的插入排序
    for i in range(gap, len(li)): #表示摸到的牌的下标
        temp = li[i] #摸到的牌的值
        j = i - gap #手里的牌的下标
        while j >= 0 and li[j] > temp:
            li[j+gap] = li[j]
            j -= gap
        li[j+gap] = temp

def shell_sort(li): #希尔排序
    d = len(li) // 2
    while d >= 1:
        insert_sort_gap(li, d)
        d //= 2

计数排序(Count Sort)

  • 统计所有元素,再判断每个元素有几个
  • 非比较排序,时间复杂度为O(n),比较排序的时间复杂度最小为O(nlogn)
  • 计数排序有限制:需要知道数的范围;需要消耗内存空间;无法小数...

代码:

def count_sort(li, max_count=100):
    count = [0 for _ in range(max_count+1)]
    for val in li:
        count[val] += 1
    li.clear()
    for ind, val in enumerate(count):
        for i in range(val):
            li.append(ind)

桶排序(Bucket Sort)

  • 计数排序中元素范围比较大的改进算法
  • 将元素分在不同的桶中,对每个桶中的元素排序
  • 桶排序的表现取决于数据的分布,也就是需要对不同数据排序时采取不同的分桶策略
  • 平均情况时间复杂度O(n+k),最坏情况O(kn^2),k=n(logn-logm),m为桶的个数
  • 空间复杂度:O(kn)

 代码:

def bucket_sort(li, n=100, max_num=10000): #n为桶的个数
    buckets = [[] for _ in range(n)] #创建桶
    for var in li:
        i = min(var // (max_num // n), n-1) #i表示var放到哪个桶里
        #如数为10000时,没有编号为100的桶,越界了,所以-1放在99号桶里
        bucket[i].append(var) #把var加到桶里
        #保持桶内的顺序
        for j in range(len(bucket[i]-1, 0, -1):
            if bucket[i][j] < bucket[i][j-1]:
                bucket[i][j], bucket[i][j-1] = bucket[i][j-1], bucket[i][j]
            else:
                break
    sorted_li = []
    for buc in buckets:
        sorted_li.extend(buc)
    return sorted_li

基数排序(Radix Sort)

  • 多关键字排序:例如先按年龄排序,再按薪资排序
  • 数字的话按位数分桶排序,有几位就循环几次
  • 时间复杂度O(kn),k是位数
  • 空间复杂度O(k+n)

代码:

def radix_sort(li):
    max_num = max(li)
    it = 0
    while 10 ** it <= max_num:
        buckets = [[] for _ in range(10)]
        for var in li:
            #987 it=1 987//10->98 98%10->8; it=3 987//100->9 9%10=9
            digit = (var // 10 ** it) % 10
            buckets[digit].append(var)
        #分桶完成
        li.clear()
        for buc in buckets:
            li.extend(buc)
        #把数重新写回li
        it += 1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值