堆是具有以下性质的完全二叉树(若设二叉树的深度为h,除第 h 层外,其它各层的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。):
每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;
或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。对堆中的结点按层进行编号,并将将这种逻辑结构映射到数组中,则有:
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
升序排序一般使用大根堆,降序排序一般使用小根堆。以升序排序为例,堆排序的大体流程主要分为两步:第一步是建立初始的大根堆,第二步是将堆顶元素与当前arr的末尾元素交换,使末尾元素最大。重复这两个步骤,直到整个序列有序。
- 建立大根堆:在建立大根堆的过程中,首先从倒数第一个非叶子结点开始(其索引为len(arr)/2 - 1)调整,如果该节点的左孩子或右孩子大于该节点,就交换使得根节点保持最大值,然后调整交换的子节点为根节点的子树;然后调整倒数第二个非叶子结点(倒数第二个非叶子结点的索引为第一个非叶子结点的索引-1,因为最后一个非叶子结点之前的结点一定都是非叶子结点,都要进行调整)。
- 将堆顶元素与当前arr的末尾元素交换,使末尾元素最大。然后对arr的前n-1个元素进行1中描述的重建大根堆的步骤。
用Python实现的代码如下:
def heapify(arr, n, i):
largest = i
l = 2 * i + 1 # left = 2*i + 1
r = 2 * i + 2 # right = 2*i + 2
if l < n and arr[i] < arr[l]:
largest = l
if r < n and arr[largest] < arr[r]:
largest = r
if largest != i:
arr[i],arr[largest] = arr[largest],arr[i] # 交换
heapify(arr, n, largest)
def heapSort(arr):
n = len(arr)
# Build a maxheap.
for i in range(n, -1, -1):
heapify(arr, n, i)
# 一个个交换元素
for i in range(n-1, 0, -1):
arr[i], arr[0] = arr[0], arr[i] # 交换
heapify(arr, i, 0)
参考资料:Python堆排序 菜鸟教程