Python数据结构与算法——排序(希尔、计数、桶、基数排序)

目录

希尔排序

计数排序

桶排序

基数排序


希尔排序

希尔排序是一种分组插入排序算法

步骤:

首先取一个整数d1 = n/2,将元素分为d1个组,每组相邻量元素之间距离为d1,在各组内进行直接插入排序;

取第二个整数d2 = d1/2,重复上述分组排序过程,直到di = 1,即所有元素在同一组内进行直接插入排序。

希尔排序每趟并不使某些元素有序,而是使整体数据越来越接近有序;最后一趟排序使所有数据有序。

希尔排序根据gap选择时间复杂度不同

from cal_time import *

# 插入排序修改
def insert_sort_gap(li, gap):
    for i in range(gap, len(li)):
        tmp = li[i]
        j = i - gap
        while j >= 0 and li[j] > tmp:
            li[j+gap] = li[j]
            j -= gap
        li[j+gap] = tmp

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

li = list(range(100000))
import random
random.shuffle(li)
shell_sort(li)

计数排序

对列表进行排序,已知列表中的数范围都在0-100之间,设计时间复杂度为O(n)的算法。

import random
from cal_time import *

@cal_time
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)
    return li

li = [random.randint(0, 100) for i in range(100000)]
count_sort(li)

桶排序

在计数排序中会出现这么一个问题:

有这样一串数字1,2,1000000,5,3,2...

其中最大数字为1000000,难道要开辟1000000大的空间来进行排序吗?

很显然浪费空间

桶排序就是计数排序的改造(使用不是很多)

桶排序:首先将元素分在不同的桶中,再对每个桶中的元素排序。

也可以边放边排序,在往桶里丢的过程中使用排序使桶内的元素有序。

桶排序的表现取决于数据的分布,也就是需要对不同数据排序时采取不同的分桶策略

平均情况时间复杂度:O(n+k)

最坏情况时间复杂度:O(n2k)

空间复杂度:O(nk)

import random
from cal_time import *


@cal_time
def bucket_sort(li, n = 100, max_num = 10000): # n表示桶的个数,max_num表示数的范围
    buckets = [[] for _ in range(100)] # 创建二维列表,列表内每一个列表是一个桶
    for var in li:
        # 现在有10000个数,100个桶,所以每个桶放100个数
        # i表示var放到几号桶里
        i = min(var // (max_num // n), n-1) # min表示如果数大于等于10000时,将这些数放到最后一个桶里
        buckets[i].append(var)  # 把var加到桶内
        # 保持桶内顺序
        for j in range(len(buckets[i]) - 1, 0, -1):
            if buckets[i][j] < buckets[i][j-1]:
                buckets[i][j], buckets[i][j-1] = buckets[i][j-1], buckets[i][j]
            else: break
    sorted_li = []
    for buc in buckets:
        sorted_li.extend(buc)
    return sorted_li

li = [random.randint(0, 10000) for i in range(100000)]
li = bucket_sort(li)

基数排序

多关键字排序:

假如现在有一个员工表,要求按照薪资排序,年龄相同的员工按照年龄排序

先按照年龄进行排序,再按照薪资进行稳定排序

对数字排序也可以看作多关键字排序

先根据个位分桶,再根据十位分桶...

时间复杂度:O(kn)

空间复杂度:O(k+n)

import random
from cal_time import *


@cal_time
def radix_sort(li):
    max_num = max(li)  # 循环次数根据最大值确定 9 -> 1 ; 99 -> 2 ; 888 -> 3 ; 10000 -> 5
    it = 0
    while 10**it <= max_num:  # 做循环
        buckets = [[] for _ in range(10)]
        for var in li:
            digit = (var // (10**it)) % 10
            buckets[digit].append(var)
        # 分桶完成
        li.clear()
        for buc in buckets:
            li.extend(buc)
        # 把数重新写回li

        it += 1


li = list(range(100000))
random.shuffle(li)
radix_sort(li)

代码自己手动敲一遍理解更深哦!

  • 19
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值