基于桶思想的排序
1. 桶思想
基数排序 vs 计数排序 vs 桶排序
以上都是利用了桶思想的排序,都属于无需比较进行排序思想里的一部分。
三者的主要区别就是。
- 计数排序:每个桶只存储单一键值;
- 基数排序:根据键值的每位数字来分配桶;
- 桶排序:每个桶存储一定范围的数值;
因为基本的都是拿空间来换时间,并且大多适用于数值范围小数据多这种场合。举几个例子。
- 测量成年人的身高(140~220)差不多都是这个区间范围内的
- 测试高考成绩(0~800) 差不多又是在这个范围内的。
不是所有的排序都适用于桶思想,要看具体的数据是什么类型!
2. 计数排序 (Counting Sort)
2-1 特点
非比较的排序方式。多适用于确定范围的整数。
是标准的用空间在换时间的排序算法。
代码实现方便,最难的地方在于理解。起码需要2个数组。
- 原始数组
- 用来计数
- 用来遍历反向输出数组
2-2 代码实现
2-2-1 思路1
""" 这个是在原来的数组上 进行重新写入覆盖的实现方式 """ from random import shuffle def counting_sort(array, maxval): # 数组长度为最大值+1 m = maxval + 1 # 新建一个长度为m全部为0的数组 count = [0] * m # 遍历所有的文字 for a in array: # a此时虽然为数组里的数字,但是作为index加入到了计数数组里面 count[a] += 1 # 默认i为0,用来计数全新产生的数组 i = 0 # 遍历所有的m,这个时候a就是0~m,0.1.2.3.4... for a in range(m): # 遍历第2个数组,这时候数值为count[a] 其实是index为0,1,2,3里面所有值的个数 # 比如这样一个数字 0出现了3次。 # 0 1 2 3 4 5 # 3 0 3 1 1 2 # 那么下面这个for c in range(count(0)) = for c in range(3) # 那么c就应该是0,1,2 # i = 0 =>array[0] = 0,array[1] = 0,array[3] = 0结束 for c in range(count[a]): array[i] = a i += 1 return array arr = [1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 8, 8, 10, 10, 12, 14, 14, 15] print("原始数组\n",arr) shuffle(arr) print("打乱之后\n",arr) maxval = max(arr) counting_sort(arr,maxval) print("排序之后\n",arr) # 原始数组 # [1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 8, 8, 10, 10, 12, 14, 14, 15] # 打乱之后 # [1, 14, 7, 1, 8, 2, 15, 4, 8, 10, 8, 3, 14, 5, 12, 4, 6, 10] # 排序之后 # [1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 8, 8, 10, 10, 12, 14, 14, 15]
2-2-2 思路2
网上查找的一个思路,生成的计数数组大小是按照 最大值-最小值+1 这个套路
def counting_sort(arr, maxVal, minVal): n =len(arr) # 计数数组长度 length = maxVal + minVal + 1 # 新建一个 排序好的数组 outArr = [0 for _ in range(n)] # 新建一个 计数数组 countArr = [0 for _ in range(length)] # 遍历所有的数字 # 然后放入 countArr # 第一个遍历结束之后得到的数组 print(countArr) # [1, 3, 1, 1, 1, 0, 2, 0, 3, 0, 0, 1, 1, 1, 0, 0, 2] for number in arr: # 这里是 根据最小数字为基准,找到合适的位置 countArr[number - minVal] += 1 # 对计数数组进行遍历 # 从第二个index开始遍历,得到一个数组 # 每个位置的值=当前值+前一个位置的值 用来统计出小于等于当前下标的元素个数 # [1, 4, 5, 6, 7, 7, 9, 9, 12, 12, 12, 13, 14, 15, 15, 15, 17] for j in range(1, length): countArr[j] = countArr[j] + countArr[j - 1] print(countArr) # 第三个反向遍历 # arr[i] 数组最后一个数字 - minVal 最小值 - 1 = 就是这个数字的该在的位置 for i in range(n-1, -1, -1): # arr[16] = 1 # countArr[1-0] = countArr[1] = 4 # outArr[4-1] = outArr[3] 也就是说 1 应该在outArr[3]的上面 outArr[countArr[arr[i] - minVal] - 1] = arr[i] # countArr[1-0] = countArr[1-0] - 1 = countArr[1] -1 = 4-1 = 3 # countArr[arr[i] - minVal] 自减 1 countArr[arr[i] - minVal] -= 1 return outArr arr = [12, 4, 11, 1, 3, 6, 8, 6, 1, 8, 2, 0, 13, 16, 16, 8, 1] print("排序之前", arr) maxVal = max(arr) minVal = min(arr) print("排序之后", counting_sort(arr, maxVal,minVal)) # 排序之前 [12, 4, 11, 1, 3, 6, 8, 6, 1, 8, 2, 0, 13, 16, 16, 8, 1] # 排序之后 [0, 1, 1, 1, 2, 3, 4, 6, 6, 8, 8, 8, 11, 12, 13, 16, 16]
2-3 注意点
添加一个函数用法的区别。
ord() ※ 文字 =>ASCII | chr()※ ASCII =>文字 | |
---|---|---|
普通 | ord("a") # 97 | chr(97) # 'a' |
转码返回10进制(Python2) | ord(u"あ") # 12354 | |
16进制(Python2) | hex(ord(u"あ")) # 0x3042 | unichr(12354) # u"\u3042" |
注意点未完待续。。
共有评论(0)