数据结构-JavaScript实现一个二分搜索树

224 阅读3分钟

二分搜索树介绍

二分搜索树:Binary Search Tree

二分搜索树有着高效的插入、删除、查询操作。

平均时间的时间复杂度为 O(log n),最差情况为 O(n)。二分搜索树与堆不同,不一定是完全二叉树,底层不容易直接用数组表示故采用链表来实现二分搜索树

数基本结构

class Node {
  constructor(val) {
    this.val = val;
    this.left = null;
    this.right = null;
  }
}

实现一个二分搜索树

1. 构造函数

class BST {
  constructor() {
    this.root = null;
    this.size = 0;
  }
}

2. 向二分搜索树中添加新的元素val

class BST {
  // ...
  // 向二分搜索树中添加新的元素val
  add(val) {
    this.root = this.addNode(this.root, val)
  }
  addNode(node, val) {
    if (node === null) {
      this.size ++;
      return new Node(val)
    }
    if (this.compareTo(node.val, val) < 0) {
      node.left = this.addNode(node.left, val)
    } else if (this.compareTo(node.val, val) > 0) {
      node.right = this.addNode(node.right, val)
    }
    return node;
  }
  // 针对整数进行简单比较
  compareTo(a, b) {
    return b - a;
  }
}

3. 查看二分搜索树中是否包含元素val

class BST {
  // ...
  // 针对整数进行简单比较
  compareTo(a, b) {
    return a - b;
  }
  // 看二分搜索树中是否包含元素e
  contains(val) {
    return this.containsNode(this.root, val);
  }
  containsNode(node, val) {
    if(node === null) {
      return false;
    }
    if (this.compareTo(node.val, val) === 0) {
      return true;
    } else if (this.compareTo(node.val, val) > 0) {
      return this.containsNode(node.left, val)
    } else {
      return this.containsNode(node.right, val)
    }
  }
}

4. 寻找找二分搜索树的最小元素和最大元素,并返回该元素对应的值

class BST {
  // ...
  // 寻找找二分搜索树的最小元素
  minimum() {
    return this.minimumNode(this.root).val
  }
  // 返回以node为根的二分搜索树的最小值所在的节点
  minimumNode(node) {
    if (node.left === null) {
      return node
    }
    return this.minimumNode(node.left)
  }
  // 寻找二分搜索树的最大元素
  maximum() {
    return this.maximumNode(this.root).val
  }
  // 返回以node为根的二分搜索树的最大值所在的节点
  maximumNode(node) {
    if(node.right === null) {
      return node
    }
    return this.maximumNode(node.right)
  }
}

5. 从二分搜索树中删除最小值所在节点和最大节点,并返回该节点

class BST {
  // ...
  // 从二分搜索树中删除最小值所在节点, 返回最小值
  removeMin() {
    let ret = this.minimum()
    this.root = this.removeMinNode(this.root)
    return ret;
  }
  removeMinNode(node) {
    if(node.left === null) {
      let rightNode = node.right
      node.right = null
      this.size --;
      return rightNode
    }
    node.left = this.removeMinNode(node.left)
    return node
  }
  // 从二分搜索树中删除最大值所在节点
  removeMax(){
    let ret = this.maximum()
    this.root = this.removeMaxNode(this.root)
    return ret
  }
  removeMaxNode(node) {
    if(node.right === null) {
      let leftNode =  node.left
      node.left = null
      this.size --;
      return leftNode
    }
    node.right = this.removeMaxNode(node.right)
    return node;
  }
}

6. 从二分搜索树中删除元素为val的节点

class BST {
  // ...
  // 从二分搜索树中删除元素为val的节点
  remove(val) {
    this.root = this.removeNode(this.root, val)
  }
  // 删除掉以node为根的二分搜索树中值为val的节点, 递归算法
  // 返回删除节点后新的二分搜索树的根
  removeNode(node, val) {
    if(node === null) {
      return null;
    }
    if (this.compareTo(node.val, val) === 0) {
      // 待删除节点左子树为空的情况
      if(node.left === null) {
        let rightNode = node.right
        node.right = null
        this.size --;
        return rightNode
      }
      // 待删除节点右子树为空的情况
      if (node.right === null) {
        let leftNode = node.left
        node.left = null
        this.size --;
        return leftNode
      }
      
      // 如果左右子树都不为空时,寻找该节点的后继successor
      // 后继: 比待删除节点大的最小节点, 即待删除节点右子树的最小节点
      // 用这个节点顶替待删除节点的位置
      let successor = this.minimumNode(node.right)
      let rightNode = this.removeMinNode(node.right)
      
      successor.left = node.left
      successor.right = rightNode
      node.left = null
      node.right = null
      return successor
      
    } else if (this.compareTo(node.val, val) > 0) {
      node.left = this.removeNode(node.left, val)
      return node
    } else {
      node.right = this.removeNode(node.right, val)
      return node
    }
  }
}

7. 二分搜索树的前序遍历

class BST {
  // ...
  // 二分搜索树的前序遍历
  preOrder() {
    this.preOrderNode(this.root)
  }
  preOrderNode(node) {
    if(node === null) {
      return;
    }
    // 重点是这个 console 的位置
    console.log(node.val)
    this.preOrderNode(node.left)
    this.preOrderNode(node.right)
  }
}

8. 二分搜索树的中序遍历

二分搜索树的中序遍历结果时顺序的

class BST {
  // ...
  // 二分搜索树的中序遍历
  inOrder() {
    this.inOrderNode(this.root)
  }
  inOrderNode(node) {
    if(node === null) {
      return;
    }
    this.inOrderNode(node.left)
    console.log(node.val)
    this.inOrderNode(node.right)
  }
}

9. 二分搜索树的后序遍历

class BST {
  // ...
  // 二分搜索树的后序遍历
  postOrder() {
    this.postOrderNode(this.root)
  }
  postOrderNode(node) {
    if(node === null) {
      return;
    }
    this.postOrderNode(node.left)
    this.postOrderNode(node.right)
    console.log(node.val)
  }
}