- 待排序的项称为 记录 (record),每个记录包含一个 关键字 (key),即排序问题中要重排的值,记录的剩余部分由 卫星数据 (statellite data)组成。
- 如果输入数组中仅有常数个元素需要在排序过程中存储在数组之外,则称排序算法是 原址的 (in place)。插入排序可以在$\Theta(n^2)$时间内将n个数排好序,是一种非常快的原址排序算法;归并排序有更好的渐近运行时间$\Theta(n\lg n)$,但它使用的MERGE过程并不是原址的。
算法 | 最坏情况运行时间 | 平均情况/期望运行时间 |
---|---|---|
插入排序 | $\Theta(n^2)$ | $\Theta(n^2)$ |
归并排序 | $\Theta(n\lg n)$ | $\Theta(n\lg n)$ |
堆排序 | $O(n\lg n)$ | — |
快速排序 | $\Theta(n^2)$ | $\Theta(n\lg n)$(期望) |
计数排序 | $\Theta(k+n)$ | $\Theta(k+n)$ |
基数排序 | $\Theta(d(n+k))$ | $\Theta(d(n+k))$ |
桶排序 | $\Theta(n^2)$ | $\Theta(n)$(平均情况) |
堆排序
算法 | 时间复杂度 | 空间原址性 |
---|---|---|
插入排序 | $O(n^2)$ | 是 |
归并排序 | $O(n\lg n)$ | 否 |
堆排序 | $O(n\lg n)$ | 是 |
堆
-
计算父节点、左右孩子节点下标
PARENT(i) return i/2 LEFT(i) return 2i RIGHT(i) return 2i+1
-
最大堆除了根以外的所有节点 i 满足:$A[\rm{PARENT}(i)]\geq A[i]$
-
最小堆除了根以外的所有节点 i 满足:$A[\rm{PARENT}(i)]\leq A[i]$
-
对于完全二叉树,叶节点数 = 非叶节点数 或 非叶节点数+1
维护堆的性质
MAX-HEAPIFY(A, i) 通过逐级下降,使得下标为 i 的根节点的子树符合最大堆的性质
MAX-HEAPIFY(A, i)
l = LEFT(i)
r = RIGHT(i)
if l <= A.heap-size and A[l] > A[i]
largest = l
else
largest = i
if r <= A.heap-size and A[r] > A[largest]
largest = r
if largest != i
exchange A[i] with A[largest]
MAX-HEAPIFY(A, largest)
每个孩子的子树的大小最多为 $2n/3$(最坏情况发生在树的最底层半满的时候),故MAX-HEAPIFY运行时间 $T(n) \leq T(2n/3) + \Theta(1)$,解为$T(n) = O(\lg n)$。
建堆
BUILD-MAX-HEAP 把大小为 n = A.length 的数组 A[1..n] 转换为最大堆。
BUILD-MAX-HEAP(A)
A.heap-size = A.length
// 子数组 $A(n/2+1..n)$ 中的元素都是叶节点
for i = A.length/2 downto 1
MAX-HEAPIFY(A, i)
- 渐近上界 BUILD-MAX-HEAP 需要调用MAX-HEAPIFY O(n) 次,故总的时间复杂度为 $O(n\lg n)$,或者$O(nh)$。
- 更加紧确 含n个元素的堆高度为 $\lfloor \lg n\rfloor$,高度为h的元素数最多为 $\lceil n/2^{h+1} \rceil$,于是 BUILD-MAX-HEAP的时间复杂度为 $O\left( \sum_{h=0}^{\lfloor \lg n\rfloor} \lceil n/2^{h+1} \rceil O(h) \right) = O\left(n\sum_{h=0}^{\lfloor \lg n\rfloor}\frac{h}{2^h}\right) = O\left(n\sum_{h=0}^{\infty}\frac{h}{2^h}\right) = O(n)$
堆排序算法
HEAPSORT(A)
BUILD-MAX-HEAP(A)
for i = A.length downto 2
exchange A[1] wiith A[i]
A.heap-size = A.heap-size - 1
MAX-HEAPIFY(A, 1)
MAX-HEAPIFY 时间复杂度为 $O(\lg n)$,被HEAPSORT n-1 次调用,故 HEAPSORT 的时间复杂度为 $O(n\lg n)$
优先队列
- 优先队列 是一种用来维护由一组元素构成的集合S的数据结构,每个元素有一个相关的值,称为 关键字 (key)。优先队列同样有两种形式: 最大优先队列 和 最小优先队列 。
- 一个最大优先队列支持以下操作:
- INSERT(S, x):把元素x插入集合S中。
- MAXINUM(S):返回S中具有最大关键字的元素。
- EXTRACT-MAX(S):去掉并返回S中具有最大关键字的元素。
- INCREASE-KEY(S, x, k):将元素x的关键字值加到k
- 最大优先队列用于共享计算机系统的作业调度,最小优先队列用于基于事件驱动的模拟器(关键字为事件发生时间)。
HEAP-MAXINUM(A)
return A[1]
HEAP-EXTRACT-MAX(A)
if A.heap-size < 1
error "heap underflow"
max = A[1]
A[1] = A[A.heap-size]
A.heap-size = A.heap-size - 1
MAX-HEAPIFY(A, 1)
return max
HEAP-EXTRACT-MAX 的时间复杂度为 $O(\lg n)$(取决于MAX-HEAPIFY的时间复杂度)。
HEAP-INCREASE-KEY(A, i, key)
if key < A[i]
error "new key is smaller than current key"
A[i] = key
while i > 1 and A[PARENT(i)] < A[i]
exchange A[i] with A[PARENT(i)]
i = PARENT(i)
HEAP-INCREASE-KEY 中当前元素不断与父元素比较,当前元素大则将二者交换,直至当前元素的关键字小于父节点。时间复杂度为$O(\lg n)$。
MAX-HEAP-INSERT(A, key)
A.heap-size = A.heap-size + 1
A[A.heap-size] = - MAX_INT
HEAP-INCREASE-KEY(A, A.heap-size, key)
MAX-HEAP-INSERT的时间复杂度为$O(\lg n)$。