调整大顶堆
这是堆排序的基本操作,单独拿出来看得更清楚
代码
def heapadjust(arr, start, end): # 将以start为根节点的堆调整为大顶堆
temp = arr[start]
# 二叉树编号为1~n,比列表索引大1
son = 2 * start + 1
while son <= end:
if son < end and arr[son] < arr[son + 1]: # 找出左右孩子节点较大的
son += 1
if temp >= arr[son]: # 判断是否为大顶堆
break
arr[start] = arr[son] # 子节点上移
print("子节点上移",end="")
print(arr)
start = son # 继续向下比较
son = 2 * son + 1
arr[start] = temp # 将原堆顶插入正确位置
print(arr)
案例
例子1
先看一个简单的例子
array = [1,2,3,4,5]
heapadjust(array, 1, 5) # 1对应最后一个非叶子结点5的索引
heapadjust(array, 0, 5) # 0对应根节点的索引
从最后一个非叶结点开始调整直到根节点都被调整,这里就是最后一个非叶子结点就是5索引为1,根节点的1索引为0,这样调整两次。
例子2
将那个例子加一个数,稍微加深一下理解
array = [1,2,3,4,5,6]
heapadjust(array, 2, 5) # 2对应最后一个非叶子节点索引
heapadjust(array, 1, 5)
heapadjust(array, 0, 5) # 0对应根节点索引
主要的变化在于需要多调用一次调整的方法
小结
由上面两个例子可以看出,通过循环即可调整给定列表为大顶堆。
array = [1,2,3,4,5,6]
n=len(array)
#建立大顶堆
root=n//2-1 #最后一个非叶节点(完全二叉树中)
while(root>=0):
heapadjust(array, root, n-1)
root-=1
执行的结果当然和例子中,手动分布执行的结果相同。
交换
接着上面的例1
array = [5, 4, 3, 1, 2] # 之前构造好的大顶堆
n=len(array)
# 第一次交换取出最大
(array[0], array[n-1]) = (array[n-1], array[0]) # 将大顶堆堆顶数放到最后
heapadjust(array, 0, n-2) # 调整剩余
# 第二次交换取出次大
(array[0], array[n-2]) = (array[n-2], array[0]) # 将大顶堆堆顶数放到最后
heapadjust(array, 0, n-3) # 调整剩余
# 第三次交换取
(array[0], array[n-3]) = (array[n-3], array[0]) # 将大顶堆堆顶数放到最后
heapadjust(array, 0, n-4) # 调整剩余
# 第四次交换取
(array[0], array[n-4]) = (array[n-4], array[0]) # 将大顶堆堆顶数放到最后
heapadjust(array, 0, n-5) # 调整剩余
每次将堆顶元素即最大元素放到最后,剩余元素重新调整为大顶堆,使得剩余的最大元素能到顶堆。
接着将上述过程修改为循环
array = [5, 4, 3, 1, 2]
n=len(array)
i = n - 1 # 记录剩余元素部分最后一个元素对应的索引
while (i > 0):
(array[0], array[i]) = (array[i], array[0]) # 将大顶堆堆顶数放到最后
heapadjust(array, 0, i - 1) # 调整剩余数组成的堆
i -= 1
封装
最后将上述两个过程封装成可供外界调用的堆排序函数,以下代码来自另一篇博客。
def HeapSort(lst):
def heapadjust(arr,start,end): #将以start为根节点的堆调整为大顶堆
temp=arr[start]
son=2*start+1
while son<=end:
if son<end and arr[son]<arr[son+1]: #找出左右孩子节点较大的
son+=1
if temp>=arr[son]: #判断是否为大顶堆
break
arr[start]=arr[son] #子节点上移
start=son #继续向下比较
son=2*son+1
arr[start]=temp #将原堆顶插入正确位置
#######
n=len(lst)
if n<=1:
return lst
#建立大顶堆
root=n//2-1 #最后一个非叶节点(完全二叉树中)
while(root>=0):
heapadjust(ls,root,n-1)
root-=1
#掐掉堆顶后调整堆
i=n-1
while(i>=0):
(lst[0],lst[i])=(lst[i],lst[0]) #将大顶堆堆顶数放到最后
heapadjust(lst,0,i-1) #调整剩余数组成的堆
i-=1
return lst
调用起来看看
array = [1,3,6,2,4,5]
print(HeapSort(array))
成功得到升序排列的数组