修改二叉搜索树
Posted
技术标签:
【中文标题】修改二叉搜索树【英文标题】:Modify a binary search tree 【发布时间】:2016-11-25 17:21:43 【问题描述】:我正在尝试为二叉搜索树类编写一个方法来修改平衡的正常树,使树仅在一侧有节点。
从元素出现在不平衡树中的顺序来看,对我来说,顺序遍历(左、中、右)之间似乎存在某种关系。
【问题讨论】:
如果你在课堂上得到了这个作业,我希望你的老师会提前提供足够的材料来完成这个作业;所以你的问题应该被提出来的合适的一方就是你的导师。 这不是课堂作业@SamVarshavchik,我正在练习 感谢@melpomene 在问题中进行了编辑 @SamVarshavchik 不要责怪教练,除非你比我们有更多的信息。 @nicomp 但它很有趣! 【参考方案1】:void unbalance(Node **pp)
Node *p;
while ((p = *pp))
if (!p->left)
pp = &p->right;
else
Node *tmp = p->left->right;
*pp = p->left;
p->left->right = p;
p->left = tmp;
...
Node *tree = ...;
unbalance(&tree);
此代码基于@templatetypedef 的回答。它使用指针对指针来避免孤立节点(这也摆脱了finalRoot
,其唯一目的是避免孤立调用者传入的原始根)。
这个想法是沿着最右边的树枝走下树。如果没有任何左孩子,我们只进入if
语句的第一部分并退出而不做任何事情。
当有左子树时使用else
部分。在这种情况下,我们向右旋转树。
这具有从左子树上拉一个节点的效果,即我们的左子树现在小了一个节点。我们重复这个直到左子树完全消失,此时我们再次进入if
的第一部分。然后我们下到剩下的右子树并重复整个过程。
指针对指针在修改链表或树的结构时通常很有用。它们让我们直接处理原始指针,而不是复制它们。在这种情况下,赋值*pp = ...
修改了别处的指针(pp
指向的指针)。这要么是原始根(由调用者传入),要么是树中的right
指针之一(由pp = &p->right
设置)。之所以需要重新指向,是因为 else
分支中的树旋转会打乱节点周围的节点,因此曾经是子树的根的会被进一步向下移动,而之前的左节点被拉上来成为新的根。我们更新*pp
以保留更高的指针(调用者中的tree
变量或父节点的right
成员)指向子树的(新)根的不变量。
【讨论】:
非常感谢!这适用于我正在使用的实现。您能否详细说明一下您对 Node ** 的使用以及它有何帮助?是不是因为它是开始的参考,因此实际上反映了变化?你能告诉我你用什么软件/网站制作动画吗? @C2K 我从en.wikipedia.org/wiki/Tree_rotation 偷了动画(实际上我只是热链接了它)。它由“Tar-Elessar”创建,位于CC BY-SA 4.0。【参考方案2】:迭代执行此操作的一种方法是使用树旋转。这个想法是这样的:
-
如果根节点有左子节点,则向右旋转根节点。
否则,根节点没有左子节点。向右下降并重复此过程。
在伪代码中:
Node finalRoot = null;
while (currNode != null)
if (currNode.left != null)
currNode = rotateRight(currNode);
else
if (finalRoot == null) finalRoot = currNode;
currNode = currNode.right;
return finalRoot;
这种方法改编自 Day-Stout-Warren 算法,这是第一步。它的运行时间为 O(n)。
【讨论】:
if (finalRoot == null)
部分让我感到困扰:它不优雅。现在我知道原因了:它处理原始根指针(currNode
的初始值)与所有其他指针 currNode
步骤不同(所有 .right
子级)。我认为这意味着伪代码已损坏:它不会更新currNode.right
,因此树无法访问所有被轮换的左侧节点。
所以finalRoot
实际上并不是最初的树根——它最终成为树中最右边的节点(跟踪示例树上的代码)。另外,您能详细说明一下丢失节点的情况吗?当我们下降到右子树时,我们知道没有左子树可以丢失(而且我们上面的所有东西都在一个巨大的脊柱中。)
这是我正在谈论的图表:i.imgur.com/P1qPc1m.png - 这有意义吗?关键是A.right
永远不会更新,因此一直指向B
,即使B
不再是其子树的根。
@melpomene 我确实尝试过运行伪代码,但似乎我在我的 3 树中丢失了一个节点......当我有一个可行的解决方案时会对其进行更多研究并更新。
@templatetypedef 这是理解 Day-Stout-Warren 算法的好读物吗? penguin.ewu.edu/~trolfe/DSWpaper我正在尝试理解正确的旋转以上是关于修改二叉搜索树的主要内容,如果未能解决你的问题,请参考以下文章