我试图在堆的最后一级找到最合适的节点( tree representation ,以便删除最小/最大堆中的特定元素 .
几乎所有网上人都写了用最低级别的堆的最右边节点替换要删除的节点 - 我完全理解但是如何才能找到最后一个节点?
Solution according to me :我有一个解决方案,即使用级别顺序遍历(广度优先搜索)遍历该树(堆结构),同时存储节点的地址 - 一旦在队列中只剩下一个没有子节点的元素时,我将它用于替换 . 此示例中最右边的节点是 33 :
有没有其他方法/链接可以使用,因为使用队列似乎相当冗长?
1 回答
让我们看一个完整的二叉树,忽略存储在节点上的值,但是编号节点as if they were stored in an array,从根开始编号:
如果我们从根遍历到任何目标节点(根本身除外),左边缘(红色)0,右边缘(蓝色)1,我们看到一个模式:
从根到所需节点的路径与该节点(root为1)的二进制表示相同,忽略最重要的二进制数字!
因此,在一个完整的树中,为了到达第一个节点,根为1,我们首先找到小于
K
的两个最大幂,并按照下面的二进制数字,按降序遍历,零指示左,一个权利 .假设我们的节点结构类似于
然后找到
i
th节点,i = 1
为root,可以实现为实际上,如果您有一个包含
N
节点的完整二叉树,ith_node(root, N)
将返回指向最终节点的指针 .如果你想要路径,最低有效位是来自root的第一个边,你可以使用例如
注意,上面的函数是在完成的树上预测的:即,除了可能是最后一个之外的所有级别都被填充,最后一级填充了所有最左边的节点 . 也就是说,如果填充了使用上图所示编号的节点N,则还必须填充节点1至N-1 .
上例中的逻辑有效 . 但是,由于示例代码是在没有经过适当审核的情况下编写的,因此可能存在错误 . 因此,如果您对示例代码有任何疑问,或者确实在此答案中有任何问题,请在评论中告诉我,以便我可以根据需要进行检查和修复 .
请注意,二进制堆通常使用数组表示 .
(为了使用正确的数组索引,我们在这里切换到从零开始的索引;即从这一点开始,根在索引0处 . )
然后节点没有指针 . 为了支持删除,我们通常将索引存储到节点所在的堆数组中,但是节点只包含数据 . (如果你需要更改键值,或者删除root以外的条目,你通常会添加一个指定当前堆数组索引的数据字段 . 虽然它确实有点慢,所以通常不需要它 . 我会省略它为简单起见 . )
请注意,
heap
中的引用数组是根据需要动态分配/重新分配的,因此堆的大小没有固有的限制(当然除了内存) .HEAP_INIT
宏允许在声明时初始化堆 . 换句话说,heap h = HEAP_INIT;
相当于heap h; heap_init(&h);
.将新元素添加到这样的堆中非常简单:
在堆数组中,如果您有
n
个节点,则索引为i
的节点(根目录为索引为0)父母在索引
(i - 1)/2
当且仅当i > 0
当且仅当
2*i+1 < n
时,索引为2*i+1
的左子正确的孩子在索引
2*i+2
当且仅当2*i+2 < n
级别
k
的节点索引是连续的,从(1 << k) - 1
到(2 << k) - 2
,包括(当root具有索引0和级别0时) .索引为
i
(索引为0且级别为0的根)的级别为k
,为floor(log2(i+1))
或通过以下函数获取:同样,上面示例中的逻辑有效 . 但是,由于示例代码是在没有经过适当审核的情况下编写的,因此可能存在错误 . 因此,如果您对示例代码有任何问题,或者确实存在任何问题回答,请在评论中告诉我,以便我可以根据需要进行检查和修复 .