算法导论:堆排序
维护堆
主要思想
- 比较
和 的大小 - 如果
不是最大的,则将其与比较大的孩子节点进行交换 - 在堆中继续向下比较和交换,直到
节点为根的子树是一个大顶堆
伪代码
Max-Heapify(A, i, n) {
l = Left(i);
r = Right(i);
if(l <= n && A[l] > A[i]) largest = l;
else largest = i;
if(r <= n && A[r] > A[largest]) largest = r;
if(largest != i) {
swap(A[i], A[largest]);
Max-Heapify(A, largest, n);
}
}
运行时间为
建堆
主要思想
自底向上把一个无序的数组建成大顶堆。
- 在建堆的过程中,只需要考虑非叶节点
- 子数组
中的元素对应的所有节点都是叶子结点
伪代码
Build-Max-Heap(A, n) {
for(i = n/2; i >= 1; i--) {
Max-Heapify(A, i, n);
}
}
效率分析
简单界:Max-Heapify
,每次调用需要
准确界:堆的高度是
- 最多有
个高度为 的节点 - 在高度为
的节点上运行Max-Heapify
的时间是
因此建堆的总代价是:
堆排序
主要思想
- 在数组上建立大顶堆
- 从根节点开始,将根节点与数组最后一个元素进行交换
- “去掉”数组中最后一个元素,然后在新的根节点上调用
Max-Heapify
- 重复上面两个步骤,直到只剩下一个节点
伪代码
HeapSort(A, n) {
Build-Max-Heap(A, n);
for(i = n; i > 1; i--) {
swap(A[1], A[i]);
Max-Heapify(A, 1, i-1);
}
}
效率分析
- 建堆:
for
循环 次swap
:Max-Heapify
:
故总时间为
优先队列
:增加元素 的
- 确保
- 更新
的 - 向上遍历树,比较
和它的父节点,有需要就交换值,直到 的 比它的父节点小
Increase-Key(A, i, key) {
if(key < A[i]) return;
A[i] = key;
while(i > 1 && A[Parent(i)] < A[i]) {
swap(A[i], A[Parent(i)]);
i = Parent(i);
}
}
时间:
:将元素 插入集合
- 增加堆的大小
- 在堆的最后一个位置增加一个
为 的节点 - 增加
到 ,调用
Insert(A, key, n) {
n = n + 1;
A[n] = -inf;
Increase-Key(A, n, key)
}
时间:
:去掉并返回集合 中 最大的元素
- 确保堆不空
- 复制最大元素(根节点)
- 把树中最后一个节点变成新的根节点
Extract-Max(A, n) {
if(n < 1) return;
max = A[1];
A[1] = A[n];
n = n - 1;
Max-Heapify(A, 1, n);
return max;
}
时间:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步