计数排序-桶排序-基数排序
计数排序
计数排序的实现主要是数据样本的特殊性(正整数,明确最大边界)和利用列表索引位置来记录值,索引值来统计个数
最后循环索引,根据值(个数)确定添加多少个
import time def cal_time(func): def wrapper(*args, **kwargs): t1 = time.time() result = func(*args, **kwargs) t2 = time.time() print("%s running time: %s secs." % (func.__name__, t2 - t1)) return result return wrapper @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) @cal_time def sys_sort(li): li.sort() import random, copy li = [random.randint(0,100) for _ in range(100000)] li1 = copy.deepcopy(li) li2 = copy.deepcopy(li) count_sort(li1) sys_sort(li2)
桶排序
桶排序实现思路和计数排序实现思路大体相同,计数排序是通过列表索引来把相同的数弄到一组,而桶排序则是确定一个范围来确定分组
代码实现思路:
- 根据桶数和最大数确定放入哪个桶
- 桶内进行冒泡排序
import random def bucket_sort(li, n=100, max_num=10000): 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 li = [random.randint(0,10000) for i in range(100000)] # print(li) li = bucket_sort(li) print(li)
桶排序不是一种特别理想的排序,如果数据分布不均匀,过多的数落入到一两桶里,排序效果就跟冒泡排序没有多大差别
基数排序
基数排序实现思路是多关键词排序和桶排序的结合,多关键词排序,举个例子,你就明白了,比如先工资排序,如果相同的再按年龄排序
基数排序实现过程:
- 先对个位进行排序,个数为相同的放同一个桶,合并桶
- 在对合并桶数据的十位排序,十位相同放一个桶中,合并桶
- 循环上述过程,个十百千万...
代码实现要点:获取最大数确定循环位数,每次循环桶数确定0-9,分桶合并桶
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: # 987 it=1 987//10->98 98%10->8; it=2 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
基数排序在某些情况下,比快速排序还快,是一种比较理想的排序,算法复杂度接近O(kn),它运算快慢更多取决于列表中数字大小,如果很大,它就会慢下来,而快排则是取决于列表长度,所以要根据不同场景来使用这个两个算法