algorithm - 如何将二叉树原地转换成堆?
问题描述
我想到了以下几点:
- 将树退化为链表,在退化的同时,将节点对象及其在链表中的索引组成一个动态数组
它看起来像这样
def treeDegenerator(self): self.valList = [] currentNode = self self.totalNodes = 0 self.nodes = 0 while currentNode: while currentNode.getLeftChild(): currentNode.rotate_root_right() self.valList.append(currentNode) currentNode = currentNode.getRightChild() self.totalNodes += 1
- 使用动态数组,取消引用所有左孩子和右孩子,并使用(索引值)* 2 + 1将退化树转换为完整的树,得到左孩子,右边再加1。
def completeTree(): for node in self.valList: node.left = None node.right = None for i in range(len(self.valList)): self.valList[i].left = self.valList[(i)*2+1] self.valList[i].right = a.valList[(i)*2+2]
- 通过从底部开始逐级比较每个节点的子节点,通过移位值变成堆。
这是一个学生必须在没有任何过去考试参考的情况下编写代码的问题。我的方法的问题是,我几乎不可能在 30 分钟内正确地写下所有代码,如果我事先记住一些代码,也许有可能。我想知道是否有更简单、更可行和优雅的解决方案将任何二叉树变成一个堆?
解决方案
从概念上讲,您可以将此任务分解为两个步骤:
- 将树重建为完美平衡的 BST,底部行从左到右填充。您可以使用Day-Stout-Warren 算法的修改版本来做到这一点。
- 运行heapify 算法将你的树转换成二叉堆。这可以非常漂亮地递归完成;详情见下文。
Day-Stout-Warren 算法的工作原理是将树旋转成单链表,然后从那里应用一系列旋转将其变成完美平衡的树。我不记得 DSW 算法是否专门将所有剩余节点放置在最左边的树的底层,根据二进制堆的需要。如果没有,您可以通过清理过程来解决此问题:如果树没有完美的 2 次幂的节点数,则从树的底层删除所有节点,然后使用为了遍历将它们放在最左边。
至于 heapify 算法:这通常是通过从底部到顶部访问树的层来完成的。对于每个节点,您反复将该节点与其较小的子节点交换,直到它小于其所有子节点。使用显式树结构,这可以通过优雅的递归策略来完成:
- 如果树没有孩子,就停下来。
- 否则,递归地堆积左子树和右子树,然后执行“冒泡”传递,反复将根的值与其较小的孩子的值交换,直到它在正确的位置。
这总体上需要 O(n) 时间并且仅使用 O(log n) 辅助存储空间,这是堆栈帧实现这两种算法所需的空间。
<editorializing> 话虽如此 - 这似乎是一个非常糟糕的编码问题,无法进行 30 分钟的定时考试。您可以很好地掌握算法以及如何对其进行编码,但却不记得这里两个子步骤中涉及的所有步骤。在半小时内提出这个问题,本质上是在测试“你是否已经非常详细地记住了各种不相关算法的实现?”,这似乎不是一个好的目标。</编辑>
推荐阅读
- c# - C# SQL 连接 ODBC 或 OLEDB
- javascript - 类变量的正确类型(例如 fArr = Uint32Array)
- reactjs - 如果 action id 不存在,则 React/Redux 更新状态数组
- c# - 为什么反射器不显示IDictionary
实现 IEnumerable ? - javascript - react-native 包指定了一个主模块 https 模块
- javascript - 在 HTML5 视频标签上强制硬件加速(每个 html 或 js)
- edi - 如何区分 Liaison Delta 和 ECS 中的 XML 事务
- bash - 如何根据特定条件删除具有不同扩展名的文件?
- android - MaterialButton 在 Android 5.1.1(API 级别 22)中看起来不像“MaterialButton”
- java - 如何使用已生成的 AES 256 GCM 96 密钥(来自 Hashicorp Vault)加密数据?