Python树的右旋转异常:节点丢失与无限循环问题排查
为什么你的二叉树右旋转函数失效?
让我们一步步拆解问题所在,先回忆下二叉树右旋转的核心逻辑:把当前节点t的左孩子l升级为新根,t降级为l的右孩子,同时把l原来的右子树挂到t的左孩子位置,还要严格维护所有节点的parent指针——这两点你的代码都没做到位,导致了丢失节点和无限循环的问题。
问题1:节点引用关系完全搞反,导致丢失节点
你的代码里做了很多多余且错误的赋值操作:
- 你单独保存了
t.right、t.left.right、t.left.left,然后错误地执行t.right.right = r、t.right.left = lr这类操作。比如当你旋转根节点n_12时:- 你把
t替换成了原来的左孩子n_3,然后把t.right设为n_12 - 接着你把
n_12的右孩子重新赋值为它自己原来的右孩子n_15(这步完全没必要,n_12.right本来就是n_15) - 最致命的是,你把
n_12的左孩子设为了lr(也就是原来n_1的右孩子n_2),这直接覆盖了n_12原本的左子树n_3的左分支(n_1、n_not1这些节点),自然就丢失了部分节点。
- 你把
正确的逻辑应该是:只需要处理t的左子树和l的右子树的挂载关系,不需要动t原本的右子树——它在旋转后依然是t的右子树,不需要重新赋值。
问题2:完全没维护parent指针,导致无限循环
当你调用rightRotate(n_1)时,你的代码只修改了n_not1.right = n_1,但:
- 没有把
n_1的parent更新为n_not1 - 没有把
n_1的left设为n_not1原来的右子树(这里是None) - 也没有更新
n_not1的parent为原来n_1的父节点n_3
这就导致n_1.left依然指向n_not1,而n_not1.right指向n_1,形成了循环引用——后续遍历这个结构时就会无限循环。
问题3:多余的赋值操作
代码里的if ll != None: t.left = ll完全是画蛇添足:t本身就是原来的t.left(也就是l),它的左孩子本来就是ll,这步操作不会改变任何状态,反而增加了代码复杂度。
修复后的右旋转函数
下面是符合正确逻辑的实现,同时严格维护parent指针:
def rightRotate(t): if t is None or t.left is None: return t # 不满足旋转条件时返回原节点,而非None l = t.left lr = l.right # 暂存l的右子树 # 把lr挂载到t的左子树,并更新parent t.left = lr if lr is not None: lr.parent = t # 把t挂载到l的右子树,并更新parent l.right = t t.parent = l # 更新l的parent为原t的parent,并调整原父节点的子节点指向 l.parent = t.parent if l.parent is not None: if l.parent.left == t: l.parent.left = l else: l.parent.right = l return l # 返回旋转后的新根节点
修复后的效果:
- 调用
rightRotate(n_12):n_3会成为新根,n_12降级为n_3的右孩子,n_3原来的右子树n_7会挂载到n_12的左孩子位置,所有节点的parent指针都正确关联,不会丢失任何节点。 - 调用
rightRotate(n_1):n_not1成为新节点,n_1成为它的右孩子,n_1的左孩子被设为None,n_not1的parent更新为n_3,彻底避免了循环引用。
内容的提问来源于stack exchange,提问作者Ele975




