Skip to content

二叉搜索树

简介

二叉搜索树(Binary Search Tree, BST)又叫有序二叉树

特点:每个节点的值大于其左子树中所有节点的值,并且小于其右子树中所有节点的值

操作的平均时间复杂度:

  • 插入操作:O(log n)
  • 删除操作:O(log n)
  • 查询操作:O(log n)

中序遍历打印结果是有序的

因为二叉搜索树的构建与插入顺序有关,极端情况下会形成链表,导致插入、删除、搜索时间复杂度降为 O(n),所以才有 AVL 树、红黑树等平衡二叉树概念,降低操作的复杂度

代码实现

ts
class TreeNode {
    public value: number;
    public left: TreeNode | null;
    public right: TreeNode | null;

    constructor(value: number) {
        this.value = value;
        this.left = null;
        this.right = null;
    }
}

function inOrderTraversal(root: TreeNode | null): void {
    if (!root) {
        return;
    }

    inOrderTraversal(root.left);
    console.log(root.value);
    inOrderTraversal(root.right);
}

class BinarySearchTree {
    public root: TreeNode | null;

    constructor() {
        this.root = null;
    }

    // 插入新节点
    public insert(value: number): void {
        const newNode = new TreeNode(value);

        if (this.root === null) {
            this.root = newNode;
        } else {
            this.__insertNode(this.root, newNode);
        }
    }

    private __insertNode(currentNode: TreeNode, newNode: TreeNode): void {
        if (newNode.value < currentNode.value) {
            if (currentNode.left === null) {
                currentNode.left = newNode;
            } else {
                this.__insertNode(currentNode.left, newNode);
            }
        } else {
            if (currentNode.right === null) {
                currentNode.right = newNode;
            } else {
                this.__insertNode(currentNode.right, newNode);
            }
        }
    }

    // 删除节点
    public delete(value: number): void {
        this.root = this.__deleteNode(this.root, value);
    }

    private __deleteNode(node: TreeNode | null, value: number): TreeNode | null {
        if (node === null) return null;

        if (value < node.value) {
            node.left = this.__deleteNode(node.left, value);
        } else if (value > node.value) {
            node.right = this.__deleteNode(node.right, value);
        } else {
            // 删除情况一:删除叶子节点,直接删除该节点即可
            // 删除情况二:只有一个子节点,用子节点替换当前节点
            if (node.left === null) return node.right;
            else if (node.right === null) return node.left;

            // 删除情况三:有两个子节点
            // 找到该节点中序遍历的后继节点,用后继节点的值替换删除节点的值,再删除后继节点
            // 后继节点必然是右子树的最左叶子节点
            node.value = this.__findMinValue(node.right);
            node.right = this.__deleteNode(node.right, node.value);
        }

        return node;
    }

    private __findMinValue(node: TreeNode): number {
        let current = node;
        while (current.left !== null) {
            current = current.left;
        }

        return current.value;
    }

    // 搜索节点
    public search(value: number): TreeNode | null {
        return this.__searchNode(this.root, value);
    }

    private __searchNode(node: TreeNode | null, value: number): TreeNode | null {
        if (node === null || node.value === value) {
            return node;
        }

        if (value < node.value) {
            return this.__searchNode(node.left, value);
        } else {
            return this.__searchNode(node.right, value);
        }
    }
}

// 使用示例
const bst = new BinarySearchTree();
const keys = [2, 1, 3, 5, 4, 7, 6];
keys.forEach((key) => bst.insert(key));

console.log('查看构建结果');
inOrderTraversal(bst.root);

bst.delete(3);
bst.delete(5);
console.log('\n查看删除3、5节点后的结果');
inOrderTraversal(bst.root);

console.log('\n查看搜索节点:7');
console.log(bst.search(7));
console.log('查看搜索节点:8');
console.log(bst.search(8));

基于 MIT 许可发布