JavaScript 数据结构:树的介绍与实现

133 阅读3分钟

树是一种常见的非线性数据结构,它由节点(Node)和边(Edge)组成,每个节点包含一个值以及指向其他节点的引用。树广泛应用于各种算法和系统中,如文件系统、游戏开发等。

本文将简要介绍树的基本概念、常见类型以及如何在 JavaScript 中实现树。

1. 树的基本概念

树由以下几个基本部分组成:

  • 根节点(Root):树的起始节点。
  • 节点(Node):树中的每个元素,包含数据和指向子节点的引用。
  • 边(Edge):连接父节点和子节点的连接。
  • 父节点(Parent):一个节点直接连接的上一级节点。
  • 子节点(Child):一个节点直接连接的下一级节点。
  • 叶子节点(Leaf):没有子节点的节点。
  • 深度(Depth):节点到根节点的路径长度。
  • 高度(Height):节点到最远叶子节点的路径长度。

2. 常见的树类型

  • 二叉树(Binary Tree):每个节点最多有两个子节点(左子节点和右子节点)。
  • 平衡二叉树(AVL Tree):自平衡的二叉树,保证左右子树的高度差不超过1。
  • 二叉搜索树(Binary Search Tree, BST):二叉树的特殊形式,左子树节点值小于父节点,右子树节点值大于父节点。
  • 堆(Heap):一种特殊的完全二叉树,分为最大堆和最小堆,根节点的值最大或最小。
  • B 树(B-Tree):B 树是一种自平衡的多路查找树,它保证了所有叶子节点的深度相同,且每个节点可以有多个子节点。

3. 在 JavaScript 中实现树

下面我们通过实现一个简单的二叉树来展示如何在 JavaScript 中构建树。

3.1 定义树节点

首先,我们需要定义一个树节点类,每个节点包含数据、左子节点和右子节点。

class TreeNode {
  constructor(value) {
    this.value = value;  // 节点的值
    this.left = null;     // 左子节点
    this.right = null;    // 右子节点
  }
}

3.2 创建二叉树类

接下来,定义一个 BinaryTree 类,提供插入节点和遍历树的方法。

class TreeNode {
    constructor(value) {
        this.value = value; // 节点的值
        this.left = null; // 左子节点
        this.right = null; // 右子节点
    }
}

class BinaryTree {
    constructor() {
        this.root = null; // 树的根节点
    }

    // 插入节点
    insert(value) {
        const newNode = new TreeNode(value);
        if (this.root === null) {
            this.root = newNode;
        } else {
            this._insertNode(this.root, newNode);
        }
    }

    // 递归插入节点,比当前值小的插入到左子树,比当前值大的插入到右子树->这里其实是实现了二叉搜索树
    _insertNode(node, newNode) {
        if (newNode.value < node.value) {
            if (node.left === null) {
                node.left = newNode;
            } else {
                this._insertNode(node.left, newNode);
            }
        } else {
            if (node.right === null) {
                node.right = newNode;
            } else {
                this._insertNode(node.right, newNode);
            }
        }
    }

    // 中序遍历:左 -> 根 -> 右
    inOrderTraversal(node = this.root) {
        if (node !== null) {
            this.inOrderTraversal(node.left);
            console.log(node.value);
            this.inOrderTraversal(node.right);
        }
    }

    // 前序遍历:根 -> 左 -> 右
    preOrderTraversal(node = this.root) {
        if (node !== null) {
            console.log(node.value);
            this.preOrderTraversal(node.left);
            this.preOrderTraversal(node.right);
        }
    }

    // 后序遍历:左 -> 右 -> 根
    postOrderTraversal(node = this.root) {
        if (node !== null) {
            this.postOrderTraversal(node.left);
            this.postOrderTraversal(node.right);
            console.log(node.value);
        }
    }
}

const tree = new BinaryTree();

tree.insert(10);
tree.insert(5);
tree.insert(15);
tree.insert(3);
tree.insert(7);
tree.insert(12);
tree.insert(18);

// 中序遍历
console.log('中序遍历:');
tree.inOrderTraversal(); // 输出: 3, 5, 7, 10, 12, 15, 18

// 前序遍历
console.log('前序遍历:');
tree.preOrderTraversal(); // 输出: 10, 5, 3, 7, 15, 12, 18

// 后序遍历
console.log('后序遍历:');
tree.postOrderTraversal(); // 输出: 3, 7, 5, 12, 18, 15, 10

二叉树的形状

1926a93c77326ea866cde46fdbeee172.png