希尔排序
# 希尔排序
# 希尔排序是对插入排序的升级改造
# 它的大致流程是
# 1、将长度为n的序列 分为d = n//2组
# 2、使每一组变的有序
# 3、将序列分为 d1 = d // 2 组
# 4、将每一组变的有序
# 5、直到最后 d 小于等于 0
def inster_sort_gap(li,gap):
for i in range(gap,len(li)):
tmp = li[i]
j = i - gap
while j >= 0 and tmp > li[j]:
li[j+gap] = li[j]
j -= gap
li[j+gap] = tmp
def shell_sort(li):
n = len(li)
gap = n // 2
while gap > 0:
inster_sort_gap(li,gap)
gap //= 2
计数排序
#计数排序
对列表进行排序,已知列表中的数范围都在0到100之间。
设计时间复杂度为O(n)的算法
#eg:
1 3 2 4 1 2 3 1 3 5
# 分配0-5六个桶,遇到一个数,在相应的桶上加一
0
1 1+1+1
2 1+1
3 1+1+1
4 1
5 1
复杂度 O(n)
占用空间 O(n)
# 计数排序
def count_sort(li, max_count):
count = [0 for _ in range(max_count+1)]
for i in li:
count[i] += 1
li.clear()
for ind, val in enumerate(li):
for i in range(val):
li.append(ind)
桶排序
# 如果计数排序中,如果元素的范围比较大(比如在1到1亿之间),如何改造算法
# 桶排序(Bucket Sort):
把元素放在不同的桶里,对每个桶里面的元素保持有序
def bucket_sort(li,n=100,max_num=10000):
"""
:param li: 需要排序的列表
:param n: 分多少个桶
:param max_num: 最大数
:return:
"""
buckets = [[] for _ in range(n)]
for var in li:
i = min(var // (max_num // n), n-1) # i 表示var放到几号桶里面
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
# 范围特别大,用的不是太多
# 桶排序的效率
# 取决于数据的分布,也就是需要对不同数据排序时,采取不同的分桶策略
# 平均分布---
# 不平均,90%的数在某一个桶里
#
# 平均情况时间复杂度:O(n+k)
# 最坏情况时间复杂度:O(n**2k)
# 空间复杂度:O(nk)
# 还可以优化,比如内部排序过程
基数排序
# 先行知识点: 基于多关键字排序
eg:对员工表进行薪资排序,薪资相同的按照年龄排序
先按照年龄进行排序,再按照薪资进行稳定的排序
#对 32,13,19,52,54,94,3,17 的排序,也可以看作是多关键字排序
#先对个位数进行桶排序,再对十位数进行桶排序
时间复杂度,O(kn)
空间复杂度,O(k+n)
k表示数字位数
快排 nlogn # logn=log(2,n)
计数排序 kn # k=log(10,n)
当长度是固定的,数值范围越来越大,达到一定程度100000000...,基数排序的性能会变差
缺陷在于,需要占用空间
字符串的排序
# abcd
# ab00 #在面加0
数字排序,是在前面001 ,012,123
小数?
# 基数排序
def radix_sort(li):
max_num = max(li) # 取出最大值,99->2, 888->3, 10000->5
it = 0 # 7--> it=0 77-->it=2, it等于0的时候,取个位数,it=1的时候,取的是十位数
while 10 ** it <= max_num: # 在每次里面进行分桶
buckets = [[] for _ in range(10)] # 0-9 共计 10个 桶
for var in li:
# 分到几号桶,看的是哪一位的数
# 怎么取出对应位置上的数字
# 987 it=0 取第一位7 987%10=7
# it=1 取第二位8 987//10=98 98%10=8
# it=2 取第三位9 987//100=9 9%10=9
# 所以,公式: (987//10**it) % 10
digit = (var // 10 ** it) % 10
buckets[digit].append(var)
# 已经做好了分桶
# 把数重新写进li
li.clear()
for buc in buckets:
li.extend(buc)
it += 1