用Python实现堆排序:(一)利用向堆中插入数据的思想初始化堆
参考书籍:《我的第一本算法书》
实现语言:Python
(一)堆的要点:
(1)堆可以看作一颗完全二叉树,其根节点除外,其任意一个节点,总是大于或等于它的父节点(最小堆)或是小于等于它的父节点(最大堆) 。
(2)最小堆中,节点的排列顺序为从上到下,每个节点分支上的数字越往下越大,同一行顺序从左到右,但同一行兄弟节点之间没有大小关系可言,最大堆反之。
最小堆:
(二)往堆中插入元素(以最小堆为例)
(1)注意要点:在最小堆中存储数据时,子节点必定大于父节点,因此最小值被存储在顶端的根节点中,往最小堆中添加数据时,为了满足这一条规则,一般会把新数据放在最下面一层靠左的位置,如果最下面一层没有多余的空间时,就另起一行,把数据从这一行最左端开始添加,直到这一行又没位置时,又起一行如此反复
总结为:
(1)每插入一个数字i,先将其放置在最后一层靠左的位置,然后判断是否小于其父节点,若小于则将它们两个数字进行替换。
(2)第一步替换完成后,此时数字i处于其父节点处,继续判断其是否小于新的父节点,若小于继续交换,如此反复,直到新插入进来的数字不小于其父节点的数字时,或者其已经被替换到了根节点时,算是插入成功
(三)插入数字图解
▪️首先插入数字3,是堆中的第一个节点
▪️接着插入数字5,其比3大,所以不用交换
▪️插入数字2,此时数的最下面一层靠左还有一个位置,数字2插入,但是由于其小于父节点3的值,所以将它们交换
▪️插入数字7,此时树的最下面一层已经没有位置了,所以需要重起一行,将7插入到新的一行靠左的位置,并且7大于其父亲节点的值5,所以不需要进行交换
▪️插入数字6,根据规则,放置在5的右子节点,且大于5,所以不需要置换
▪️插入数字8,根据规则,放置在3的左子节点上,且大于3,不需要置换
▪️插入数字9,9也如此,不需要置换,放置在3的右子节点
▪️
(1)插入数字1,因为最后一层没有位置了,所以另起一行,放置在了7的左子节点。
(2)由于1小于其父节点7,将它们进行置换。
(3)此时1又小于其新的父节点5,将它们再次置换。
(4)置换过后1又比 根节点2小,再次进行置换,此时1已经被放置到了根节点处,触发停止条件,此次插入停止。
(四)代码块
import math
# 初始序列:[3, 5, 2, 7, 6, 8, 9, 1] 调整后的堆序列:[1, 2, 3, 5, 6, 8, 9, 7]
def IntoHeap(array):
# 创建空堆,等待被无序数组中的数字依次插入
heap = [array[0]]
# (1)往堆中依次插入数字,(2)在while循环中调整该数字在堆中的位置
for i in range(1, len(array)):
heap.append(array[i])
# 用来记录插入到堆中的数据当前移动到哪个节点及其对应的父亲节点
now_node = i
now_parent_node = math.ceil(0.5 * now_node) - 1
# 直到当前被调整的节点小于自己的父节点时或者当前节点已经被调整到根节点时,停止这一轮进堆操作(把>=号换成<=号就实现了最大堆的初始化)
while not (heap[now_node] >= (heap[now_parent_node]) or now_node == 0):
# 当前节点大于自己的父节点,将该节点和其父亲节点进行交换
heap[now_node], heap[now_parent_node] = heap[now_parent_node], heap[now_node]
# 交换完成后,重新定义当前被调整的节点以及算出其父亲节点的位置,准备进行下一次while循环
now_node = now_parent_node
now_parent_node = math.ceil(0.5 * now_node) - 1
return heap
print(IntoHeap([3, 5, 2, 7, 6, 8, 9, 1]))
(五)结果(在代码中插入了一些print语句输出每次插入数据的操作过程,在第四部的代码块中删掉了)
插入数字:3
[3]
插入数字:5
[3, 5]
插入数字:2
[2, 5, 3]
[2, 5, 3]
插入数字:7
[2, 5, 3, 7]
插入数字:6
[2, 5, 3, 7, 6]
插入数字:8
[2, 5, 3, 7, 6, 8]
插入数字:9
[2, 5, 3, 7, 6, 8, 9]
插入数字:1
[2, 5, 3, 1, 6, 8, 9, 7]
[2, 1, 3, 5, 6, 8, 9, 7]
[1, 2, 3, 5, 6, 8, 9, 7]
(六)总结:
根据堆的插入过程总结出来的一种方法,对自己来说算是比较好理解的,之后会总结另外一种初始化堆的方法,然后再到堆排序,若写的存在问题,欢迎指正。