You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

二叉搜索树节点添加与中序遍历原理咨询

BST的addNode与inOrderTraversal递归逻辑及this用法解析

先贴一段典型的Java BST实现代码(匹配你提到的方法结构),所有讲解基于这段代码展开:

class BST {
    // 内部节点类
    class Node {
        int val;
        Node left;
        Node right;
        Node(int val) {
            this.val = val;
        }
    }

    private Node root;

    // 对外暴露的添加入口
    public void add(int val) {
        root = addNode(root, val);
    }

    // 核心递归添加方法
    private Node addNode(Node current, int val) {
        // 递归终止:找到插入位置,返回新节点
        if (current == null) {
            return new Node(val);
        }

        // 递归分支:处理左/右子树
        if (val < current.val) {
            current.left = addNode(current.left, val);
        } else if (val > current.val) {
            current.right = addNode(current.right, val);
        }
        // 重复值不处理(BST默认规则)
        return current;
    }

    // 对外暴露的中序遍历入口
    public void inOrder() {
        inOrderTraversal(root);
    }

    // 核心递归中序遍历方法
    private void inOrderTraversal(Node current) {
        // 递归终止:空节点直接返回
        if (current == null) {
            return;
        }
        // 中序顺序:左子树 → 当前节点 → 右子树
        inOrderTraversal(current.left);
        System.out.print(current.val + " ");
        inOrderTraversal(current.right);
    }
}

一、addNode方法的递归逻辑

递归的本质是把大问题拆成重复的小问题,每次只处理当前节点,子树交给递归调用:

  1. 终止条件:当current为null时,说明找到了空的插入位置,直接返回一个新的Node对象。
  2. 分支处理:
    • 若插入值val小于当前节点的val,则递归处理左子树,把返回的节点(新节点或原左子树节点)赋值给current.left,更新左子树的引用。
    • 若val大于当前节点的val,同理递归处理右子树,更新current.right。
    • 若值相等,直接返回原节点(BST通常不存储重复值)。
  3. 返回当前节点:每次递归调用都会更新子节点的引用,返回当前节点是为了让上层调用能正确更新父节点的左/右指针,保证树结构的完整性。

实例演示(插入序列:5→3→7)

  • 第一次调用addNode(null,5):返回新节点Node(5),root被赋值为该节点。
  • 插入3:调用addNode(root(5),3),3<5,触发addNode(null,3)返回Node(3),赋值给5.left,最终返回5,root不变。
  • 插入7:调用addNode(root(5),7),7>5,触发addNode(null,7)返回Node(7),赋值给5.right,最终返回5,root不变。

二、inOrderTraversal方法的递归逻辑

中序遍历的固定顺序是左子树 → 当前节点 → 右子树,递归严格遵循这个顺序执行:

  1. 终止条件:当current为null时,直接返回(空树或叶子节点的子树无需处理)。
  2. 执行步骤:
    • 先递归遍历左子树:一直深入到左子树的最底层叶子节点的左子节点(null),触发终止返回。
    • 然后访问当前节点:这里的“访问”是打印节点值(你也可以改成其他操作)。
    • 最后递归遍历右子树:同样深入到右子树的最底层叶子节点的右子节点(null),触发终止返回。

实例演示(基于上面的树:根5,左3,右7)

  • 调用inOrderTraversal(5),先执行inOrderTraversal(3)。
  • inOrderTraversal(3)先调用inOrderTraversal(null)(返回),然后打印3,再调用inOrderTraversal(null)(返回),回到上层。
  • 回到inOrderTraversal(5),打印5,然后执行inOrderTraversal(7)。
  • inOrderTraversal(7)先调用inOrderTraversal(null)(返回),打印7,再调用inOrderTraversal(null)(返回),结束。
  • 最终输出:3 5 7

三、this关键字结合点符号的用法

在这段代码里,this的作用非常明确,分两种场景:

  1. Node构造器中:this.val = val
    • this指代当前正在创建的Node实例,用来区分成员变量val和构造器的参数val(变量重名时必须用this明确指向成员变量)。
  2. BST类的方法中(比如this.root)
    • this指代当前BST对象实例,用来明确访问的是当前实例的成员变量root。如果没有重名变量,this可以省略,但写上能让代码更清晰,避免歧义。

四、递归图绘制技巧(帮你理清逻辑)

如果画递归图,建议结合调用栈+节点树:

  • 每一次递归调用就往调用栈里加一层,标注当前处理的节点和参数。
  • 遇到终止条件(current为null)时,从栈顶开始返回,标注返回值(新节点或null)。
  • 对于遍历方法,标注每一步的“访问”(打印)动作。

比如addNode插入3的调用栈:

1. addNode(5,3) → 进入,判断3<5,调用addNode(null,3)
2. addNode(null,3) → 终止,返回Node(3)
回到1:将5.left赋值为Node(3),返回5

中序遍历的调用栈:

1. inOrderTraversal(5) → 调用inOrderTraversal(3)
2. inOrderTraversal(3) → 调用inOrderTraversal(null)
3. inOrderTraversal(null) → 终止,返回
回到2:打印3,调用inOrderTraversal(null)
4. inOrderTraversal(null) → 终止,返回
回到1:打印5,调用inOrderTraversal(7)
5. inOrderTraversal(7) → 调用inOrderTraversal(null)
6. inOrderTraversal(null) → 终止,返回
回到5:打印7,调用inOrderTraversal(null)
7. inOrderTraversal(null) → 终止,返回
回到1:结束

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 16:40:27