堆(heap)
堆(heap)
(二叉)堆是一种用数组表示的完全二叉树,并且任意节点满足的大小关系(最大堆):
完全二叉树:对于高度为h的二叉树,除了h层以外,其余0到h-1层的节点都是满的,且h层的节点都靠左边。
完全二叉树高度:对于n个节点的完全二叉树,高度为:
证明:
对于拥有个节点的完全二叉树的高度都是h
所以根据推出,n个节点的完全二叉树高度为
建堆(makeHeap)
建堆的过程就是将初始化输入的数组重新排列,使其满足的大小关系。
假设对于元素,其左右子节点和作为根的二叉树已经满足堆的顺序性质了,那么这时只要将元素不断和左右子节点进行比较,并将和最大的子节点交换顺序,直到就是最大的节点,或者变为了叶子节点。最终就得到了更大的堆,不断进行这个过程,将子堆两两合并,最终整个数组就变成了一个完整的堆了。
这里有个很巧妙的计算过程,那就是从节点递减遍历到节点,对每个节点执行上述的步骤,便完成了建堆操作:
- 代码实现(C++):
#include <utility>
#define PARENT(i) (i / 2)
#define LEFT(i) (i * 2)
#define RIGHT(i) (i * 2 + 1)
template<typename RandomAccessIterator, typename SizeType, typename Compare>
void heapify(RandomAccessIterator first, SizeType i, SizeType size, Compare comp) {
auto val = std::move(*(first + i - 1));
for (auto child = RIGHT(i); child <= size; i = child, child = RIGHT(i)) {
if (comp(*(first + child -1 - 1), *(first + child - 1))) {
--child;
}
if (comp(val, *(first + child - 1))) {
*(first + i - 1) = std::move(val);
return;
}
*(first + i - 1) = std::move(*(first + child - 1));
}
auto leftChild = LEFT(i);
if (leftChild <= size && !comp(val, *(first + leftChild - 1))) {
*(first + i - 1) = std::move(*(first + leftChild - 1));
i = leftChild;
}
*(first + i - 1) = std::move(val);
}
template<typename RandomAccessIterator, typename Compare>
void makeHeap(RandomAccessIterator first, RandomAccessIterator last, Compare comp) {
auto size = last - first;
for (auto i = PARENT(size); i > 0; --i) {
heapify(first, i, size, comp);
}
}
#undef PARENT
#undef LEFT
#undef RIGHT
- 算法复杂度
- 最好情况:当输入数组本身就满足堆的顺序性质,那么遍历的时候什么也不用做,总共遍历了个元素,时间复杂度为
- 最坏情况:当输入的数组逆序,每个元素都需要下降到叶子节点,时间复杂度为
最坏情况计算过程:
对于包含个元素的堆,层最多包含个元素,每个元素最多下降2次,层最多包含个元素,每个元素最多下降3次,以此类推得到总的下降次数:
由于等差乘等比数列公式,其中,,所以上式中,
对于第层的元素单独计算,这里面有个元素最多下降1次
最后还有一个地方没有考虑到,那就是对于下降到这些节点的元素,由于这里已经是叶子节点了,所以之前的计算多计算了一次下降过程,且多计算的次数刚好就是这些节点数,所以最后得到:
这个结果不一定完全准确,但已经和最坏情况很接近很接近了,算法导论里面的方法估算出的是,比这里的界要松。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)