之前在Stack Exchange中已经提出过这个问题,但是没有得到答复 .
链接到之前提出的问题:Binary Heap Implemented via a Binary Tree Structure
如何在二叉树中实现堆 . 要实现堆,了解最后一个填充节点和第一个未占用节点非常重要 . 这可以在树的级别排序中完成,但是时间复杂度将是O(n)以便找到第一个未占用的节点 . 那么,如何在O(logn)中的二叉树中实现堆?
谢谢Shekhar
之前在Stack Exchange中已经提出过这个问题,但是没有得到答复 .
链接到之前提出的问题:Binary Heap Implemented via a Binary Tree Structure
如何在二叉树中实现堆 . 要实现堆,了解最后一个填充节点和第一个未占用节点非常重要 . 这可以在树的级别排序中完成,但是时间复杂度将是O(n)以便找到第一个未占用的节点 . 那么,如何在O(logn)中的二叉树中实现堆?
谢谢Shekhar
7 回答
我的堆实现
要使用具有O(log n)时间复杂度的二叉树实现堆,您需要将节点总数存储为实例变量 .
假设我们有10个总节点的堆 .
如果我们要添加一个节点......
我们将节点总数增加1 . 现在我们有11个节点 . 我们将新的节点总数(11)转换为其二进制表示:1011 .
利用总节点(1011)的二进制表示,我们摆脱了第一个数字 . 之后,我们使用011在树中导航到下一个位置以插入节点.0表示向左移动,1表示向右移动 . 因此,对于011,我们会向左走,向右走,向右走...这会将我们带到下一个要插入的位置 .
我们检查了每个级别一个节点,使得时间复杂度为O(log n)
您不会实现堆IN二进制树,因为堆是二叉树 . 堆维护以下顺序属性 - 给定节点V,其父级大于或等于V.此外,堆完成binary tree . 我在uni有ADS课程所以我会在答案的后面给你用Java实现堆 . 只列出您获得的主要方法复杂性:
size()O(1)
isEmpty()O(1)
insert()O(logn)
removeMin()O(logn)
min()O(1)
这是我的
Heap.java
文件:给你O(logn)性能的有趣部分是
downHeapBubble()
和upHeapBubble()
方法 . 我很快就会对它们加上很好的解释 .将新节点插入堆时使用
upHeapBubble()
. 所以当你插入插入到最后一个位置然后你需要像这样调用upHeapBubble()
:然后将最后一个元素与它的父元素进行比较,如果父元素更大 - swap:这是完成max logn times,其中n是节点数 . 这就是登录性能 .
对于删除部分 - 您只能删除min - 最高节点 . 所以当你删除它时 - 你必须将它与最后一个节点交换 - 但是你必须保持堆属性,你必须做一个
downHeapBubble()
. 如果节点大于它's child swap with the smallest one and so on until you don' t还有剩下的孩子,或者你没有小孩子 . 这可以在最大logn时间完成,因此这里有登录性能 . 您可以通过查看二叉树图片来解释自己为什么可以通过最大日志时间完成此操作hereHEAP IMPLEMENTATION USING TREE
我正在回答我自己的问题,它采用O(log n),但限制是保持指向父项的指针 . 如果我们不保留指向父节点的指针,我们需要大约O(n) . 我发布了这个问题以获得O(log n)的解决方案
以下是计算下一个未占用叶子的步骤(我们有一个指向父节点的指针):
这是O(log n),但需要指向父级的指针 .
O(n)解决方案非常简单,只需对树进行级别排序,我们就可以获得下一个未占用节点的位置 .
我的问题是:如何在不使用父指针的情况下在O(log n)中找到下一个未占用的节点 .
谢谢 .
假设您想使用 linked 二叉树,没有指向父节点的指针,那么我能想到的唯一解决方案就是保持每个节点中子节点数的计数器 .
此策略还 balancer 每个子树每侧的节点数,这是有益的(尽管非常轻微) .
这是O(log n) . 跟踪插入计数需要一直到屋顶,但这不会改变此操作的O(lon n)性质 . 与删除类似的事情 .
其他操作是通常的,并保持其性能特征 .
您是否需要详细信息或更喜欢自己解决?
如果你想使用一个链接的二叉树,没有除左右指针之外的其他信息,那么我建议你发起至少100,000点的赏金 . 我不是说这是不可能的(因为我没有数学证明它),但我说这几十年都没有发现(我知道) .
二叉树可以用数组表示:
用法:
请注意,BTreePrinter是我在Stackoverflow中长期使用的代码,我修改为使用2位数字 . 如果我们移动到3位数字,它将被破坏,它只是为了简单理解堆结构的外观 . 修复3位数字是为了将所有内容保持为3的倍数 . 同样归功于Sesh Venugopal在Youtube上关于Heap数据结构的精彩教程