堆排序
1 基础概念
堆,也叫 二叉堆,是一个数组,树的每个节点对应数组一个元素。
- 堆排序是利用 堆进行排序的
- 堆的左右儿子没有排序关系,只需要满足上父节点小于等于(或者大于等于)儿子就行
- 堆是一种完全二叉树:完全二叉树 是 一种除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对齐的树,向左对齐指的是儿子节点放置顺序左优先,这使得堆可以利用数组来表示(普通的一般的二叉树通常用链表作为基本容器表示)
- 堆有两种类型: 大根堆 小根堆
- 两种类型的概念如下:
- 最大堆:每个结点的值都大于或等于左右孩子结点 A[PARENT(i)] ≥ A[i]
- 最小堆:每个结点的值都小于或等于左右孩子结点 A[PARENT(i)] ≤ A[i]
- 堆排序算法采用的是最大堆。最小堆通常用于构造优先队列。
- 最大堆:寻找数据流中最小的 k 个数字。
- 堆的高度为树根的高度:Θ(lgn)。堆结构上的一些基本操作的运行时间至多是与树的高度成正比。
给定下标 i
,很容易计算其父节点、左节点和右节点:
def PARENT(i):
return i / 2
def LEFT(i):
return 2 * i
def RIGHT(i):
return 2 * i + 1
堆节点的大小关系:
2 堆排序原理详解
堆排序原理:
- 首先将待排序的数组构造出一个最大堆;
- 取出这个最大堆的堆顶节点(最大值),与堆的最下最右的元素进行交换,然后把剩下的元素再构造出一个最大堆;
- 重复第二步,直到这个最大堆的长度为1,此时完成排序。
在堆中定义以下几种操作:
- 最大堆调整(Max-Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
- 创建最大堆(Build-Max-Heap):将堆中所有数据重新排序,使其成为最大堆
- 堆排序(Heap-Sort):移除位于第一个数据的根节点,并做最大堆调整的递归运算
2.1 最大堆调整(Max-Heapify)——维持堆的性质
MAX-HEAPIFY:
作用是保持最大堆的性质,是创建最大堆的核心子程序。输入为一个数组 A 和一个下标 i,A[i] 有可能小于其孩子,通过让 A[i] 在数组中 “逐层下降” ,从而使得以下标 i
为根节点的子树重新遵循最大堆的性质。
由于一次调整后,堆仍然违反堆性质,所以需要递归的测试,使得整个堆都满足堆性质。
算法图示 :
Python实现为:
注意:判断 左右儿子 的索引值,是否超出了数组的长度。
def MAX_HEAPIFY(A, i, size):
l = LEFT(i)
r = RIGHT(i)
# 挑选出最大值对应的索引
# 注意:"索引值-1" 来取出数字
if l <= len(A) and A[l - 1] > A[i - 1]:
largest = l
else:
largest = i
if r <= len(A) and A[r - 1] > A[largest - 1]:
largest = r
else:
largest = i
if largest != i:
# 将根节点与最大值点交换
A[i - 1], A[largest - 1] = A[largest - 1], A[i - 1]
# 递归进行堆最大化
MAX_HEAPIFY(A, largest, size)
所以,在最差情况下(最底层恰好半满)运行时间为:
T ( n ) = T ( 2 n / 3 ) + Θ ( 1 ) T(n)=T(2n/3)+Θ(1) T(n)</