Python堆排序
思想:
-
构建堆
-
输出堆
分析:
1. 构建堆
-
从底向上,从右往左调整堆
-
示例:图中节点表示索引
调整顺序为:3 --> 2 --> 1 --> 0
-
调整索引范围:
[0, n//2-1]
,n
为数组长度
-
-
每次调整,从上往下(构建大根堆)
-
比较父节点与子节点的最大值,将父节点与子节点的最大值交换
父节点索引:
father
子节点索引:
father*2+1
、father*2+2
注意:边界处理
- 若
n
为偶数,父节点最大索引father=n//2-1
时,子节点最大索引可达father*2+2
- 若
n
为奇数,父节点最大索引father=n//2-1
时,子节点最大索引可达father*2+1
- 若
-
示例:调整节点 1 时(构建大根堆)
注意:该示例只是为了说明思想,由于构建堆是从底向上,从右往左构建,因此,若实际中遍历至该示例的节点 1 时,该节点以下的各节点已构成堆。
-
2. 输出堆
-
将堆顶元素与堆尾元素交换,更新堆尾前一节点为新的堆尾,调整堆顶至堆尾的各元素,调整方式同上
-
不断执行上一步,直至输出所有元素
-
示例:
-
最终数组排序即为升序排列(大根堆的情况下)
附代码(Python3)
def heap_sort(nums):
n = len(nums)
# 构建大根堆
for i in range(n//2-1, -1, -1): # 从底向上,从右往左
heap_adjust(nums, i, n-1) # 调整(堆,父节点,堆尾节点)
# 输出大根堆(即升序)
for i in range(n-1, -1, -1):
nums[0], nums[i] = nums[i], nums[0] # 交换堆顶与堆尾元素,交换后的堆尾元素即输出值
heap_adjust(nums, 0, i-1) # 调整(堆,堆顶,新堆尾节点)
def heap_adjust(nums, father, end):
# 从上往下调整
child = father*2+1 # 初始孩子节点
while child <= end:
# 选择孩子节点中较大者
if child<end and nums[child+1]>nums[child]:
child += 1
# 若孩子节点大于父亲节点,则交换,更新孩子节点为新的父节点,寻找其新的孩子节点
# 否则跳出
if nums[child] > nums[father]:
nums[father], nums[child] = nums[child], nums[father]
father = child
child = father*2+1
else:
break
li = [50, 16, 30, 10, 60, 90, 2, 80, 70]
heap_sort(li)
li
[2, 10, 16, 30, 50, 60, 70, 80, 90]