0. 代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from sys import maxsize as MAX
def parent(i):
if i:
return (i // 2 - 1)
return MAX
def left(i):
return (2 * i + 1)
def right(i):
return (2 * (i + 1))
def max_heapify(arr, i, heapsize = 1):
l = left(i)
r = right(i)
largest = len(arr) # 取一个怎么都取不到的值
if l <= heapsize and arr[l] > arr[i]:
largest = l
else:
largest = i
if r <= heapsize and arr[r] > arr[largest]:
largest = r
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
max_heapify(arr, largest, heapsize)
return
def build_max_heap(arr):
heapsize = len(arr) - 1
for i in range(len(arr) // 2, -1, -1):
max_heapify(arr, i, heapsize)
return heapsize
def heapsort(arr):
heapsize = build_max_heap(arr)
for i in range(len(arr) - 1, 0, -1):
arr[0], arr[i] = arr[i], arr[0]
heapsize -= 1
max_heapify(arr, 0, heapsize)
return arr
if __name__ == '__main__':
print(heapsort([-996, 251, 0, 12, 8, 66]))
1. 堆数据结构
我们可以将堆视为一棵完全二叉树。但实际操作中并不需要定义二叉树类,只需要用数组表示即可。
(此段翻译及改写原文) 除了数组长度length以外,我们还可以定义一个属性heap-size,表示堆中多少元素存放在数组arr中。这就意味着不是所有数组中的元素都在堆中。用公式表达:0<= heap-size <= length。
《算法导论》中以数组表示堆的图示如下:
在不使用二叉树结构,即只用数组表示堆的情况下,有如下性质:
#!/usr/bin/python3
from sys import maxsize as MAX
# 用数组表示堆
heap = [1, 2, 3, 4, 5]
# 以下方法只返回下标
# 书上的i从1开始。以下代码的i从0开始
def parent(i):
if i:
return (i // 2 - 1)
return MAX
def left(i):
return (2 * i + 1)
def right(i):
return (2 * (i + 1))
2. 最大堆与最小堆
可以分为两种:
- 最大堆
- 最小堆
在最大堆中满足如下性质:
arr[parent(i)] >= a[i]
最小堆中刚好相反:
arr[parent(i)] <= arr[i]
3. 堆排序三步走
在本例中使用最大堆来进行堆排序。一般我们用最大堆进行堆排序,用最小堆实现优先队列。
可以将堆排序分解为三步:
max-heapify:时间复杂度为O(log n)build-max-heap: 时间复杂度为O(n)heapsort: 时间复杂度为O(n log n)
3.1 max-heapify方法
思想:max-heapify方法假设左右子树皆已满足二叉堆的性质,但树根可能比自己的孩子还小,所以将树根归位到应有的位置中。
教材上的伪代码改写为Python如下:
def max_heapify(arr, i, heapsize = 1):
l = left(i)
r = right(i)
largest = len(arr) # 取一个怎么都取不到的值,用于初始化
if l <= heapsize and arr[l] > arr[i]:
largest = l
else:
largest = i
if r <= heapsize and arr[r] > arr[largest]:
largest = r
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
max_heapify(arr, largest, heapsize)
return
3.2 build-max-heap方法
书上的伪代码翻译如下:
def build_max_heap(arr):
heapsize = len(arr) - 1
for i in range(len(arr) // 2, -1, -1):
max_heapify(arr, i, heapsize)
return heapsize
3.3 heapsort方法
翻译伪代码如下:
def heapsort(arr):
heapsize = build_max_heap(arr)
for i in range(len(arr) - 1, 0, -1):
arr[0], arr[i] = arr[i], arr[0]
heapsize -= 1
max_heapify(arr, 0, heapsize)
return arr
References
- 《算法导论》