堆排序时间复杂度是O(n lgn),并且具有空间原址性,即任何时候只需要常数个额外的元素空间存储临时数据。
1. 堆
(二叉)堆是一个数组,可以被看成一个近似的完全二叉树,树上每一个节点对应数组中的一个元素。除最底层外,该树是完全充满的,而且是从左向右填充。
父节点,左孩子,右孩子的下标关系:
最大堆性质:A[PARENT(i)] >= A[i] 堆中最大元素存放在根节点中
最小堆性质:A[PARENT(i)] <= A[i] 堆中最小元素存放在根节点中
高度:定义一个堆中的节点的高度就为该节点到叶节点最长简单路径上边的数目。所以一个包含n个元素的堆的高度是Θ(lgn)
一些基本过程:
MAX-HEAPIFY:时间复杂度O(lgn),它是维护最大堆性质的关键。
BUILD-MAX-HEAP:线性时间复杂度,功能是从无序的输入数据数组中构造一个最大堆。
HEAPSORT:时间复杂度O(nlgn),功能是对一个数组进行原址排序。
MAX-HEAP-INSERT,HEAP-EXTRACT-MAX,HEAP-INCREASE-KEY,HEAP-MAXIMUM:时间复杂度O(lgn),功能是利用堆实现一个优先队列。
2. 维护堆的性质
MAX-HEAPIFY:输入为一个数组A和一个下标i,并假定根节点为LEFT(i)和RIGHT(i)的二叉树都是最大堆,但A[i]可能小于其孩子。通过让A[i]的值在最大堆中逐级下降,使得下标i为根节点的子树重新遵循最大堆的性质。
对于一棵以i为根节点,大小为n的子树,MAX-HEAPIFY的时间代价包括:调整A[i],A[LEFT(i)]和A[RIGHT(i)]的关系的时间代价Θ(1),加上在一棵以i的一个孩子为根节点的子树上运行MAX-HEAPIFY的时间。最坏情况发生在树底层恰好半满的时候,这时每个孩子的子树大小至多为2n/3,有以下递归式: T(n)
<= T(2n/3) + Θ(1)
由主定理很快知道T(n) = O(lgn)
3. 建堆
把一个大小为n = A.length
的数组A[1...n]转化为最大堆,可以知道子数组中的元素都是树的叶节点。可以利用MAX-HEAPIFY自底向上建堆。
4.堆排序算法
初始时候,可以利用BUILD-MAX-HEAP将输入数组A[1..n]建成最大堆,因为A[1]为最大元素,可以与A[n]进行互换,从而放到正确的位置,这时候把节点n从堆中删除(heapsize--),并调用MAX-HEAPIFY(A,1)维护最大堆性质。
例如最大堆A[16,14,10,8,7,9,3,2,4,1],排序过程如图:
5. 优先队列
优先队列是一种用来维护一组元素构成的集合S的数据结构,其中的每一个元素都有一个相关的值,成为关键字(key)。以一个最大优先队列为例,有以下操作:
INSERT(S,x):把元素x插入集合S中。
MAXIMUM(S):返回S中具有最大键字的元素。
EXTRACT-MAX(S):去掉并返回S中具有最大键字的元素。
INCREASE-KEY(S,x,k):将元素x的关键字增加到k,假设k的值不小于x的原关键字。