You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python树的右旋转异常:节点丢失与无限循环问题排查

为什么你的二叉树右旋转函数失效?

让我们一步步拆解问题所在,先回忆下二叉树右旋转的核心逻辑:把当前节点t的左孩子l升级为新根,t降级为l的右孩子,同时把l原来的右子树挂到t的左孩子位置,还要严格维护所有节点的parent指针——这两点你的代码都没做到位,导致了丢失节点和无限循环的问题。

问题1:节点引用关系完全搞反,导致丢失节点

你的代码里做了很多多余且错误的赋值操作:

  • 你单独保存了t.rightt.left.rightt.left.left,然后错误地执行 t.right.right = rt.right.left = lr这类操作。比如当你旋转根节点n_12时:
    1. 你把t替换成了原来的左孩子n_3,然后把t.right设为n_12
    2. 接着你把n_12的右孩子重新赋值为它自己原来的右孩子n_15(这步完全没必要,n_12.right本来就是n_15
    3. 最致命的是,你把n_12的左孩子设为了lr(也就是原来n_1的右孩子n_2),这直接覆盖了n_12原本的左子树n_3的左分支(n_1n_not1这些节点),自然就丢失了部分节点。

正确的逻辑应该是:只需要处理t的左子树和l的右子树的挂载关系,不需要动t原本的右子树——它在旋转后依然是t的右子树,不需要重新赋值。

问题2:完全没维护parent指针,导致无限循环

当你调用rightRotate(n_1)时,你的代码只修改了n_not1.right = n_1,但:

  • 没有把n_1parent更新为n_not1
  • 没有把n_1left设为n_not1原来的右子树(这里是None
  • 也没有更新n_not1parent为原来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的左孩子被设为Nonen_not1parent更新为n_3,彻底避免了循环引用。

内容的提问来源于stack exchange,提问作者Ele975

火山引擎 最新活动