lst = [9, 6, 8, 3, 1, 4, 2]
你看不出这个lst有什么特别,别着急,再介绍两个概念给你
父节点,子节点
列表中的每一个元素都是一个节点,以lst[0] 为例, 他的子节点分别是lst[1],lst[2],同时我们也说lst[1]的父节点是lst[0]
我们可以计算每一个节点的子节点,假设当前节点的序号是i, 那么它的左子节点则是 i2 +1,右子节点则是i2 + 2
最大堆,最小堆
所谓最大堆就是指每一个节点的值都比它的子节点的值大, 最小堆就是指每一个节点的值都比它的子节点的值小
现在,我们再来看上面给出的列表
lst[0] = 9,它的子节点分别是lst[1]=6,lst[2]=8
lst[1] = 6,它的子节点分别是lst[3]=3,lst[4]=1
lst[2] = 8,它的子节点分别是lst[5]=4,lst[6]=2
lst[3] = 3,它的子节点分贝是lst[7]和lst[8],但这两个节点是不存在的
后面的也就不用再看了,这个列表符合最大堆的要求, 父节点的值大于两个子节点的值,而且最重要的一点, 堆中任意一颗子树仍然是堆
如何建立一个堆
关于堆的应用,非常多,比如堆排序,在应用之前,我们必须先建立一个堆, 刚才给出的列表,恰好是一个堆,如果不是堆呢,我们需要将其变成堆, 例如下面这个列表
lst = [3, 9, 2, 6, 1, 4, 8]
def adjust_heap(lst, i, size):
lchild = 2 * i + 1 # 计算两个子节点的位置
rchild = 2 * i + 2
max = i
if i < size // 2:
if lchild < size and lst[lchild] > lst[max]:
max = lchild
if rchild < size and lst[rchild] > lst[max]:
max = rchild
# 如果max != i成立,那么就说明,子节点比父节点大,要交换位置
if max != i:
lst[max], lst[i] = lst[i], lst[max]
# 向下继续调整,确保子树也符合堆的定义
adjust_heap(lst, max, size)
def build_heap(lst):
for i in range((len(lst)//2)-1, -1, -1):
adjust_heap(lst, i, len(lst))
print (lst) # 此处输出,可以观察效果
lst = [3,9,2,6,1,4,8]
build_heap(lst)
print (lst)
[3, 9, 8, 6, 1, 4, 2] [3, 9, 8, 6, 1, 4, 2] [9, 6, 8, 3, 1, 4, 2] [9, 6, 8, 3, 1, 4, 2]
[9, 6, 8, 3, 1, 4, 2]
[9, 6, 8, 3, 1, 4, 2]
堆顶元素为9,是最大值,但是从0到最后一个元素,并不是有序的
堆排序的思路
lst = [9, 6, 8, 3, 1, 4, 2]
(1)将lst[0] 与 lst[6]交换,交换后为[2, 8, 6, 4, 3, 1, 9],现在,这个堆已经被破坏掉了
(2)那么我们可以利用adjust_heap函数重新把它调整成一个堆,adjust_heap(lst,0,6), 这样调整后,lst=[8, 6, 4, 3, 1, 2, 9]
注意看lst[0]到lst[5],这个范围内的数据被调整成了一个堆,使得lst[0]也就是8是这个范围内的最大值
我们只需要重复刚才的两个步骤,就可以将堆的大小逐步缩小,同时,从后向前让整个lst变得有序
示例代码
def adjust_heap(lst, i, size):
lchild = 2 * i + 1 # 计算两个子节点的位置
rchild = 2 * i + 2
max = i
if i < size // 2:
if lchild < size and lst[lchild] > lst[max]:
max = lchild
if rchild < size and lst[rchild] > lst[max]:
max = rchild
# 如果max != i成立,那么就说明,子节点比父节点大,要交换位置
if max != i:
lst[max], lst[i] = lst[i], lst[max]
# 向下继续调整,确保子树也符合堆的定义
adjust_heap(lst, max, size)
def build_heap(lst):
for i in range((len(lst)//2)-1, -1, -1):
adjust_heap(lst, i, len(lst))
print (lst) # 此处输出,可以观察效果
lst = [3,9,2,6,1,4,8]
def heap_sort(lst):
size = len(lst)
# 建立一个堆,此时lst[0]一定是最大值
build_heap(lst)
print ('*'*20)
for i in range(size-1, -1, -1):
# 将lst[0] 与lst[i] 交换,这样大的数值就按顺序排到了后面
lst[0], lst[i] = lst[i], lst[0]
# 交换后,重新将0到i这个范围内的数据调整成堆,这样lst[0]还是最大值
adjust_heap(lst, 0, i)
print (lst,i) # 此处输出可以查看效果
heap_sort(lst)
print ('*'*20)
print (lst)
[3, 9, 8, 6, 1, 4, 2] [3, 9, 8, 6, 1, 4, 2] [9, 6, 8, 3, 1, 4, 2] ******************** [8, 6, 4, 3, 1, 2, 9] 6 [6, 3, 4, 2, 1, 8, 9] 5 [4, 3, 1, 2, 6, 8, 9] 4 [3, 2, 1, 4, 6, 8, 9] 3 [2, 1, 3, 4, 6, 8, 9] 2 [1, 2, 3, 4, 6, 8, 9] 1 [1, 2, 3, 4, 6, 8, 9] 0 ******************** [1, 2, 3, 4, 6, 8, 9]