目录
希尔排序
希尔排序是一种分组插入排序算法
步骤:
首先取一个整数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)
代码自己手动敲一遍理解更深哦!