二叉搜索树

Posted archer-fang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉搜索树相关的知识,希望对你有一定的参考价值。

二叉搜索树(BST)有时也被叫做有序二叉树或者排序二叉树是一种特别的容器类型:是一种储存数据到内存中的数据结构。二叉树允许快速查找,添加和删除元素,而且不仅可以被用于实现动态数据集,而且在查找数据表的时候可以允许通过key来查找一个元素。
二叉查找树会保持节点的key是排好序的,因此做查找或者其他操作的时候可以使用二分法
时间复杂度O(logn)

如图:左小中 中小右

技术分享图片

BinarySearchTreeNode:

import BinaryTreeNode from ‘../BinaryTreeNode‘;
import Comparator from ‘../../../utils/comparator/Comparator‘;

export default class BinarySearchTreeNode extends BinaryTreeNode {
  /**
   * @param {*} [value] - node value.
   * @param {function} [compareFunction] - comparator function for node values.
   */
  constructor(value = null, compareFunction = undefined) {
    super(value);

    // This comparator is used to compare node values with each other.
    this.compareFunction = compareFunction;
    this.nodeValueComparator = new Comparator(compareFunction);
  }

  /**
   * @param {*} value
   * @return {BinarySearchTreeNode}
   */
  insert(value) {
    if (this.nodeValueComparator.equal(this.value, null)) {
      this.value = value;

      return this;
    }

    if (this.nodeValueComparator.lessThan(value, this.value)) {
      // Insert to the left.
      if (this.left) {
        return this.left.insert(value);
      }

      const newNode = new BinarySearchTreeNode(value, this.compareFunction);
      this.setLeft(newNode);

      return newNode;
    }

    if (this.nodeValueComparator.greaterThan(value, this.value)) {
      // Insert to the right.
      if (this.right) {
        return this.right.insert(value);
      }

      const newNode = new BinarySearchTreeNode(value, this.compareFunction);
      this.setRight(newNode);

      return newNode;
    }

    return this;
  }

  /**
   * @param {*} value
   * @return {BinarySearchTreeNode}
   */
  find(value) {
    // Check the root.
    if (this.nodeValueComparator.equal(this.value, value)) {
      return this;
    }

    if (this.nodeValueComparator.lessThan(value, this.value) && this.left) {
      // Check left nodes.
      return this.left.find(value);
    }

    if (this.nodeValueComparator.greaterThan(value, this.value) && this.right) {
      // Check right nodes.
      return this.right.find(value);
    }

    return null;
  }

  /**
   * @param {*} value
   * @return {boolean}
   */
  contains(value) {
    return !!this.find(value);
  }

  /**
   * @param {*} value
   * @return {boolean}
   */
  remove(value) {
    const nodeToRemove = this.find(value);

    if (!nodeToRemove) {
      throw new Error(‘Item not found in the tree‘);
    }

    const { parent } = nodeToRemove;//找到要移除结点的父结点

    if (!nodeToRemove.left && !nodeToRemove.right) {
      // Node is a leaf and thus has no children.
      if (parent) {
        // Node has a parent. Just remove the pointer to this node from the parent.
        parent.removeChild(nodeToRemove);
      } else {
        // Node has no parent. Just erase current node value.
        nodeToRemove.setValue(undefined);
      }
    }
    else if (nodeToRemove.left && nodeToRemove.right) {
      // Node has two children.
      // Find the next biggest value (minimum value in the right branch)找到根节点的下一个相连结点(数值上的)
      // and replace current value node with that next biggest value.
      const nextBiggerNode = nodeToRemove.right.findMin();
      if (!this.nodeComparator.equal(nextBiggerNode, nodeToRemove.right)) {//如果右子树的最小节点和要删除的节点的右子节点不是同一个节点,那么就删掉右子树最小节点的值,给要删除节点赋值
        this.remove(nextBiggerNode.value);
        nodeToRemove.setValue(nextBiggerNode.value);
      } else {
        // In case if next right value is the next bigger one and it doesn‘t have left child如果右子树的最小节点和要删除的节点的右子节点是同一个节点,且右子树的那个结点无左孩子
        // then just replace node that is going to be deleted with the right node.
        nodeToRemove.setValue(nodeToRemove.right.value);
        nodeToRemove.setRight(nodeToRemove.right.right);
      }
    }
    else {
      // Node has only one child.
      // Make this child to be a direct child of current node‘s parent.
      /** @var BinarySearchTreeNode */
      const childNode = nodeToRemove.left || nodeToRemove.right;

      if (parent) {
        parent.replaceChild(nodeToRemove, childNode);
      } else {
        BinaryTreeNode.copyNode(childNode, nodeToRemove);
      }
    }

    // Clear the parent of removed node.
    nodeToRemove.parent = null;

    return true;
  }

  /**
   * @return {BinarySearchTreeNode}
   */
  findMin() {
    if (!this.left) {
      return this;
    }

    return this.left.findMin();
  }
}

BinarySearchTree:

 

import BinarySearchTreeNode from ‘./BinarySearchTreeNode‘;

export default class BinarySearchTree {
  /**
   * @param {function} [nodeValueCompareFunction]
   */
  constructor(nodeValueCompareFunction) {
    this.root = new BinarySearchTreeNode(null, nodeValueCompareFunction);

    // Steal node comparator from the root.
    this.nodeComparator = this.root.nodeComparator;
  }

  /**
   * @param {*} value
   * @return {BinarySearchTreeNode}
   */
  insert(value) {
    return this.root.insert(value);
  }

  /**
   * @param {*} value
   * @return {boolean}
   */
  contains(value) {
    return this.root.contains(value);
  }

  /**
   * @param {*} value
   * @return {boolean}
   */
  remove(value) {
    return this.root.remove(value);
  }

  /**
   * @return {string}
   */
  toString() {
    return this.root.toString();
  }
}

note:

1.BinarySearchTreeNode中remove的说明:找到要删除的结点,要删除结点的父结点,

即:

const { parent } = nodeToRemove;

然后分三种情况考虑

(1)没有左孩子也没有右孩子,如果存在父结点则,删除该节点,否则根结点置空

(2)左(this.left)右孩子(this.right)都有,找到该结点右子树最小的结点即为min进行判断

  【1】如果min!=this.right,则递归的去删除掉min所在结点,并且把min的值赋给this

   !!!【2】如果min=this.right,则this.right.left必为null,,所以把min值给this,同时,this.right=this.right.right.

(3)只有左孩子或者右孩子,如果有父结点,则用该结点的左或右孩子替换掉该结点,否则删除该结点的左或右结点,并且把该结点的左或右结点的1.值2.左孩子3.右孩子,赋值给该结点。



以上是关于二叉搜索树的主要内容,如果未能解决你的问题,请参考以下文章

代码题(10)— 二叉搜索树

代码随想录Day20-Leetcode654.最大二叉树,617.合并二叉树,700.二叉搜索树中的搜索,98.验证二叉搜索树

二叉搜索树(KV模型,二叉搜索树删除节点)

代码随想录算法训练营第14天|530.二叉搜索树的最小绝对差501.二叉搜索树中的众数236.二叉树的最近公共祖先

二叉树之二叉搜索树(BSTree)

c++:二叉搜索树BinarySortTree