📜  BST的应用(1)

📅  最后修改于: 2023-12-03 15:29:40.653000             🧑  作者: Mango

BST的应用

二叉搜索树(Binary Search Tree,简称BST)是一种基础的数据结构,在程序员的开发过程中有着广泛的应用。BST 以一种特殊的方式对数据进行组织,可以快速的进行查找、插入和删除操作,是实现高效算法和数据结构的重要基础。

基本概念

BST 是一个二叉树,具有以下特性:

  • 每个节点最多有两个子节点;
  • 左子树所有节点的键值小于父节点的键值;
  • 右子树所有节点的键值大于父节点的键值;
  • 没有键值相等的节点。

BST 的节点包含以下属性:

  • key:节点的键值,用于在 BST 中查找、插入、删除等操作;
  • value:节点值,存储与 key 相关的信息;
  • left:指向左子节点的指针;
  • right:指向右子节点的指针;
应用场景
查找

由于 BST 的特殊性质,查找操作非常高效。可以从根节点开始比较 key 值,如果小于当前节点,就往左子树查找;如果大于当前节点,就往右子树查找。这样每次可以排除一半的节点,时间复杂度为 O(log n)。

插入

插入操作也是基于二叉搜索树的特性。在 BST 中插入一个节点时,可以先进行查找操作,确定要插入的位置。插入操作的时间复杂度同样为 O(log n)。

删除

删除一个节点时,需要考虑三种情况:

  • 没有子节点:直接删除该节点;
  • 只有一个子节点:将该节点的子节点移动到该节点的位置上;
  • 有两个子节点:查找该节点右子树中的最小节点,将其值赋给要删除的节点,然后删除该最小节点。

这样可以保持原有的 BST 特性不变。与查找和插入操作类似,删除操作也具有 O(log n) 的时间复杂度。

总结

BST 是程序员常用的数据结构之一,可以应用在多种场景下,包括查找、插入、删除等基本操作。同时,BST 还可以用于实现更高级的数据结构,比如 AVL 树、RB 树等。

Markdown 代码片段:

/**
 * BST 树节点结构
 */
class BSTNode {
  constructor(key, value) {
    this.key = key;
    this.value = value;
    this.left = null;
    this.right = null;
  }
}

/**
 * 二叉搜索树实现
 */
class BST {
  constructor() {
    this.root = null;
  }

  /**
   * 插入节点
   */
  insert(key, value) {
    const node = new BSTNode(key, value);

    if (!this.root) {
      this.root = node;
      return;
    }

    let current = this.root;
    let parent;

    while (true) {
      parent = current;

      if (key < current.key) {
        current = current.left;
        if (!current) {
          parent.left = node;
          break;
        }
      } else if (key > current.key) {
        current = current.right;
        if (!current) {
          parent.right = node;
          break;
        }
      } else {
        current.value = value;
        break;
      }
    }
  }

  /**
   * 查找节点
   */
  find(key) {
    let current = this.root;

    while (current) {
      if (key < current.key) {
        current = current.left;
      } else if (key > current.key) {
        current = current.right;
      } else {
        return current;
      }
    }

    return null;
  }

  /**
   * 删除节点
   */
  remove(key) {
    let current = this.root;
    let parent = null;
    let isLeftChild = true;

    while (current.key !== key) {
      parent = current;

      if (key < current.key) {
        isLeftChild = true;
        current = current.left;
      } else {
        isLeftChild = false;
        current = current.right;
      }

      if (!current) {
        return false;
      }
    }

    if (!current.left && !current.right) { // 没有子节点
      if (current === this.root) {
        this.root = null;
      } else if (isLeftChild) {
        parent.left = null;
      } else {
        parent.right = null;
      }
    } else if (!current.right) { // 只有一个左子节点
      if (current === this.root) {
        this.root = current.left;
      } else if (isLeftChild) {
        parent.left = current.left;
      } else {
        parent.right = current.left;
      }
    } else if (!current.left) { // 只有一个右子节点
      if (current === this.root) {
        this.root = current.right;
      } else if (isLeftChild) {
        parent.left = current.right;
      } else {
        parent.right = current.right;
      }
    } else { // 有两个子节点
      const successor = this.getSuccessor(current);
      if (current === this.root) {
        this.root = successor;
      } else if (isLeftChild) {
        parent.left = successor;
      } else {
        parent.right = successor;
      }
      successor.left = current.left;
    }

    return true;
  }

  /**
   * 查找后继节点,用于 删除操作
   */
  getSuccessor(delNode) {
    let successorParent = delNode;
    let successor = delNode;
    let current = delNode.right;

    while (current) {
      successorParent = successor;
      successor = current;
      current = current.left;
    }

    if (successor !== delNode.right) {
      successorParent.left = successor.right;
      successor.right = delNode.right;
    }

    return successor;
  }

  /**
   * 中序遍历
   */
  inOrder(node) {
    if (!node) {
      return;
    }

    this.inOrder(node.left);
    console.log(node.key);
    this.inOrder(node.right);
  }

  /**
   * 前序遍历
   */
  preOrder(node) {
    if (!node) {
      return;
    }

    console.log(node.key);
    this.preOrder(node.left);
    this.preOrder(node.right);
  }

  /**
   * 后序遍历
   */
  postOrder(node) {
    if (!node) {
      return;
    }

    this.postOrder(node.left);
    this.postOrder(node.right);
    console.log(node.key);
  }
}