今天学习了3种桶排序,基数排序,计数排序,桶排序。
1.1 基数排序
- 基数排序是一种非比较型排序,步骤
- 1.创建一个下标0~9的数组,也就是桶。
- 2.依次比较待排序数组中的个位数,然后放入桶中去。
- 放入完后,我们会得到一个按照个位数排序的有顺序的10个桶。
- 3.然我们在把桶中的数字取出来,形成一个新的待排序数组。
- 4.接着在按照上面的同样的方式循环,依次比较十位,百位…
- 5.最终可以得到一个排好序的数组。
1.2 下面是基数排序代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 基数排序
def radixSort(l):
# 创建桶,0~9 共10个桶,分别记录0,1,2,3,4,5,6,7,8,9
bucket =[[],[],[],[],[],[],[],[],[],[]]
dev = 1
maxNumberLen = 1 # 代表要比较的多少位数,1:代表只比较个位,2:代表十位 ...
currentNumberLen = 1
while currentNumberLen <=maxNumberLen:
# 比较列表中数字的所有个,十位...数,然后放入桶中
for number in l:
bucket[(number//dev)%10].append(number)
if len(str(number)) > maxNumberLen:
maxNumberLen = len(str(number))
index = 0
# 从桶中取出来,排列成一个新的序列
for k,alist in enumerate(bucket):
for n in alist:
l[index] = n
index +=1
bucket[k] = [] # 清空桶里的元素
dev *=10
currentNumberLen +=1
return l
print(radixSort([123, 91, 1, 97, 17, 23, 84, 28, 72, 5, 67, 25]))
2.1 计数排序
计数排序,计数排序如同字面意思,记录每一个数字出现的次数,变相 的也就知道这个数组的顺序了。
缺点:如果待排序的数组很大,需要创建一个很大的数组来存储出现的数字的次数
- 步骤:
-
- 找到待排列数组中最大的数和最小的数,(最大的数字)-(最小的数字)+1,代表生成桶的数量。
- 循环待排列数组,将数字放入对应的桶中,并且计数+1
- 最后在从桶中按顺序取出元素,计数-1,直到循环结束。
- 可以得到一个有序的数组。
2.2 计数排序 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 计数排序
# 计数排序速度快于 比较排序算法,但需要大量的内存,当数字很大的时候
def countSort(l):
# 找到最大值
maxValue= max(l)
bucket = [0]*(maxValue+1) #创建桶的数量,我们用下标来判断数字
for n in l:
bucket[n] +=1 # 下标为n的桶,计数加1
# 计数完成后,我们在遍历出来
index= 0
for i,n in enumerate(bucket):
while n >0:
l[index] = i # 桶的下标就是元素的值,进行赋值操作
index +=1 # 数组索引+1
n-=1 #桶中的元素数量减1
return l
print(countSort([123, 91, 1, 97, 17, 23, 84, 28, 72, 5, 67, 25]))
3.1 桶排序
桶排序有些类似计数排序,也是把数放入到桶中,但是通过
映射关系
放入到桶中!!! 一个桶中会有多个数字
。
- 步骤
- 同样的创建桶
- 通过某种映射关系,把数字映射到桶中去,映射关系最好可以让每个桶中的元素均匀分配。
- 最后排序使用排序算法,排序每一个桶中的元素。
- 最后在把桶中的元素都取出来,形成一个排好序的数组。
3.2 桶排序 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 桶排序
def bucketSort(l):
# 首先将数组中的元素映射到桶中去
# 桶的数量为(最大值-最小值)+1
# 映射函数,通过((元素值)-数组最小值)//桶数的映射关系来映射,映射关系可以换成其他的,这里只是示范
maxN = max(l)
minN = min(l)
bucket = [[] for i in range((maxN-minN)+1)]
# 映射到桶中
for n in l:
bucket[(n-minN)//5].append(n)
index= 0
# 对每个桶中的元素进行排序,这里我们使用冒泡排序
for alist in bucket:
# 冒泡排序
for i in range(len(alist)):
for j in range(i+1,len(alist)):
if alist[i] > alist[j]:
alist[i], alist[j] = alist[j], alist[i]
# 排序完以后,在添加回l中
for n in alist:
l[index] = n
index +=1
return l
print(bucketSort([12, 91, 1, 97, 17, 23, 84, 28, 72, 5, 67, 25]))
4.1 堆排序
堆排序可以看看这篇文章: 图解堆排序
- 步骤
- 1.创建一个大顶堆,也就是数组满足
arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
关系 - 2.交换跟节点和最后一个节点,交换后,剪掉最后一个节点==此时也就是数组中最大的数字。
- 3.堆的长度减少了1,继续构建大顶堆,然后交换跟节点和最后一个节点,在剪掉最后一个节点。
- 4.直到堆中只剩下一个根节点,排列完成。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 堆排序
def heapSort(l):
buildMaxHeap(l)
length = len(l)-1
while length >0:
l[length] ,l[0] = l[0],l[length] # 交换跟节点和,最后一个节点
l[:length] = buildMaxHeap(l[:length])
length -= 1
return l
# 构建最大堆
def buildMaxHeap(l):
for i in range(len(l)//2,-1,-1):
heapify(l,i)
return l
def heapify(l,i):
left = 2 * i + 1 # 左孩子
right = 2 * i + 2 # 右孩子
lastgest = i # 最大的数字
if left<len(l) and l[left] > l[lastgest]:
lastgest = left
if right<len(l) and l[right] >l[lastgest]:
lastgest = right
if lastgest !=i:
l[i],l[lastgest] = l[lastgest],l[i]
heapify(l,lastgest)
return l
t = heapSort([12, 91, 1, 97, 17, 23, 84, 28, 72, 5, 67, 25])
print(t)