二叉树的故事:神奇的家谱树

67 阅读3分钟

背景
在一个神秘的魔法世界里,有一棵神奇的树叫家谱树。这棵树记录了所有魔法师的家族关系,每个节点都是一位魔法师,每个魔法师最多有两个徒弟(左徒弟和右徒弟)。

规则

  • 每个魔法师(节点)可以有 0、1 或 2 个徒弟。

  • 每个徒弟只能有一个师傅(父节点)。

  • 最顶层的魔法师是根节点(Root),没有师傅。

例子

  • 根节点:大法师梅林(Merlin)。

  • 梅林的左徒弟:魔法部长哈利(Harry)。

  • 梅林的右徒弟:占卜师赫敏(Hermione)。

  • 哈利的左徒弟:草药师纳威(Neville)。

  • 哈利的右徒弟:魔咒师罗恩(Ron)。

  • 赫敏没有徒弟。

这个家谱可以用二叉树表示:

plaintext

         梅林(Merlin)
        /           \
  哈利(Harry)     赫敏(Hermione)
   /      \
纳威(Neville) 罗恩(Ron)

二叉树的核心概念

1. 节点(Node)

每个魔法师都是一个节点,包含:

  • 数据:魔法师的名字。
  • 左指针:指向左徒弟。
  • 右指针:指向右徒弟。

2. 根节点(Root)

整棵树的起点,没有父节点(如梅林)。

3. 叶子节点(Leaf)

没有徒弟的节点(如纳威、罗恩、赫敏)。

4. 子树(Subtree)

每个节点可以看作是一棵子树的根(如哈利及其徒弟构成一棵子树)。

Java 代码:构建二叉树

1. 定义节点类

java

class WizardNode {
    String name;        // 魔法师名字(数据)
    WizardNode left;    // 左徒弟
    WizardNode right;   // 右徒弟

    // 构造函数:创建新节点
    public WizardNode(String name) {
        this.name = name;
        this.left = null;  // 初始没有徒弟
        this.right = null;
    }
}

2. 手动构建二叉树

java

public class BinaryTreeExample {
    public static void main(String[] args) {
        // 1. 创建节点(魔法师)
        WizardNode merlin = new WizardNode("梅林(Merlin)");
        WizardNode harry = new WizardNode("哈利(Harry)");
        WizardNode hermione = new WizardNode("赫敏(Hermione)");
        WizardNode neville = new WizardNode("纳威(Neville)");
        WizardNode ron = new WizardNode("罗恩(Ron)");

        // 2. 建立师徒关系(连接节点)
        merlin.left = harry;    // 梅林的左徒弟是哈利
        merlin.right = hermione; // 梅林的右徒弟是赫敏
        
        harry.left = neville;   // 哈利的左徒弟是纳威
        harry.right = ron;      // 哈利的右徒弟是罗恩

        // 3. 根节点是梅林
        WizardNode root = merlin;

        // 4. 打印二叉树结构
        System.out.println("家谱树结构:");
        System.out.println("         " + root.name);
        System.out.println("        /           \");
        System.out.println("  " + root.left.name + "     " + root.right.name);
        System.out.println("   /      \");
        System.out.println(root.left.left.name + "  " + root.left.right.name);
    }
}

运行结果

plaintext

家谱树结构:
         梅林(Merlin)
        /           \
  哈利(Harry)     赫敏(Hermione)
   /      \
纳威(Neville) 罗恩(Ron)

更复杂的二叉树:插入节点

故事扩展
后来,哈利收了一个新徒弟露娜(Luna) ,作为他的右徒弟(原来的右徒弟罗恩变成露娜的左徒弟)。

插入节点代码

java

public class BinaryTreeInsertion {
    public static void main(String[] args) {
        // 1. 构建原有二叉树
        WizardNode root = buildOriginalTree();

        // 2. 创建新节点(露娜)
        WizardNode luna = new WizardNode("露娜(Luna)");

        // 3. 插入节点:将露娜作为哈利的右徒弟
        // 注意:先保存哈利原来的右徒弟(罗恩)
        WizardNode originalRight = root.left.right;
        root.left.right = luna;  // 哈利的右徒弟变成露娜
        luna.left = originalRight;  // 露娜的左徒弟是原来的罗恩

        // 4. 打印更新后的树结构
        System.out.println("更新后的家谱树:");
        System.out.println("         " + root.name);
        System.out.println("        /           \");
        System.out.println("  " + root.left.name + "     " + root.right.name);
        System.out.println("   /      \");
        System.out.println(root.left.left.name + "    " + root.left.right.name);
        System.out.println("         /");
        System.out.println("      " + luna.left.name);
    }

    // 辅助方法:构建原有树
    private static WizardNode buildOriginalTree() {
        WizardNode merlin = new WizardNode("梅林(Merlin)");
        WizardNode harry = new WizardNode("哈利(Harry)");
        WizardNode hermione = new WizardNode("赫敏(Hermione)");
        WizardNode neville = new WizardNode("纳威(Neville)");
        WizardNode ron = new WizardNode("罗恩(Ron)");

        merlin.left = harry;
        merlin.right = hermione;
        harry.left = neville;
        harry.right = ron;

        return merlin;
    }
}

运行结果

plaintext

更新后的家谱树:
         梅林(Merlin)
        /           \
  哈利(Harry)     赫敏(Hermione)
   /      \
纳威(Neville)  露娜(Luna)
         /
      罗恩(Ron)

二叉树的应用场景

  1. 文件系统:目录结构像一棵倒挂的树。
  2. 数据库索引:B 树、B + 树用于快速查找数据。
  3. 游戏 AI:决策树(如走棋策略)。
  4. 编译原理:语法树分析代码结构。

总结:二叉树就像家族树!

  • 节点 = 魔法师,每个魔法师最多有两个徒弟。

  • 根节点 = 最顶层的大法师(如梅林)。

  • 左 / 右指针 = 指向左 / 右徒弟的魔法纽带。

构建二叉树就是建立师徒关系的过程!如果有任何疑问,欢迎随时提问! 😊