1.桶排序
将数据分到几个有序的痛刘辩,每个桶里的数据用快排,之后再把每个桶里的数据依次取出。
要求:
1.排序的数据很容易划分为m个桶,这些桶之间有着大小顺序
2.数据在各个桶中分布较均匀
3.适合用于外部排序:数据存储在外部磁盘中,数量比较大,内存有限,无法将数据全部加载到内存
举例:
比如说我们有 10GB 的订单数据,我们希望按订单金额(假设金额都是正整数)进行排序,但是我们的内存有限,只有几百 MB,没办法一次性把 10GB 的数据都加载到内存中。这个时候该怎么办呢?
1.扫描一遍文件,看订单金额范围。若最小为1,最大为10万,就可以将订单根据金额分到100个桶,第一个桶存储1~1000,依此类推。每个桶对应一个文件,并分别编号。
2.理想条件下,订单会均匀分到100个文件,每个文件大概100MB数据,将小文件一个个放到内存中,快排排序。所有文件排好序后,再根据文件编号依次读取每个小文件的数据,写入一个大文件中。
3.若一个桶中的数据很多,可以将这个桶继续划分。
2.计数排序
假设只有 8 个考生,分数在 0 到 5 分之间。这 8 个考生的成绩我们放在一个数组 A[8]中,它们分别是:2,5,3,0,2,3,0,3。
遍历一遍,得到各个分数的人数。
顺序求和,c[k]为小于等于分数k的考生人数。
从后到前依次扫描数组 A。比如,当扫描到 3 时,我们可以从数组 C 中取出下标为 3 的值 7,也就是说,到目前为止,包括自己在内,分数小于等于 3 的考生有 7 个,也就是说 3 是数组 R 中的第 7 个元素(也就是数组 R 中下标为 6 的位置)。当 3 放入到数组 R 中后,小于等于 3 的元素就只剩下了 6 个了,所以相应的 C[3]要减 1,变成 6。
扫描完后,数组按照分数从小到大有序排列。
3.基数排序
假设要比较两个手机号码 a,b 的大小,如果在前面几位中,a 手机号码已经比 b 手机号码大了,那后面的几位就不用看了。
借助稳定排序,先排最后一位,再用稳定排序往前边排序。
每一位可以用桶排序或计数排序,时间复杂度O(n),总时间复杂度O(k*n)
基数排序要求:
需要可以分割出独立的“位”来比较,而且位之间有递进的关系,如果 a 数据的高位比 b 数据大,那剩下的低位就不用比较了。
每一位的数据范围不能太大,要可以用线性排序算法来排序,否则,基数排序的时间复杂度就无法做到 O(n) 了。
def radix_sort(s):
"""基数排序"""
i = 0 # 记录当前正在排拿一位,最低位为1
max_num = max(s) # 最大值
j = len(str(max_num)) # 记录最大值的位数
while i < j:
bucket_list =[[] for _ in range(10)] #初始化桶数组
for x in s:
bucket_list[int(x / (10**i)) % 10].append(x) # 找到位置放入桶数组
print(bucket_list)
s.clear()
for x in bucket_list: # 放回原序列
for y in x:
s.append(y)
i += 1
if __name__ == '__main__':
a = [334,5,67,345,7,345345,99,4,23,78,45,1,3453,23424]
radix_sort(a)
print(a)
4.如何根据年龄给100w用户排序
我们假设年龄的范围最小 1 岁,最大不超过 120 岁。我们可以遍历这 100 万用户,根据年龄将其划分到这 120 个桶里,然后依次顺序遍历这 120 个桶中的元素。这样就得到了按照年龄排序的 100 万用户数据。