数据结构 - 二叉搜索树

347 阅读4分钟

定义

二叉搜索树:一种树型结构,每个节点的值都大于它左子数的任一节点,并且小于右子树的任一节点

那么树中

  • 最小值就是 左子树一路向左查找,左子树为空则根节点最小
  • 最大值就是 右子树一路向右查找,右子树为空则根节点最大

二叉搜索树插入

插入流程:

  1. 从根节点开始对比,如果大于则放到右子树,小于放到左子数
  2. 从1中的新的节点开心进行对比,直到位置 为空可以存储此数据
// 插入 1  // 和15对比小于,则放到左边,和9进行对比,继续...
  (1)15                 15                15              15
   /    \             /    \            /    \          /    \
  9     23    ==> (1)9     23   ==>    9     23  ===>  9     23
 / \   /  \         / \   /  \        / \   /  \      / \   /  \
3  12 17  28       3  12 17  28    (1)3  12 17  28    3  12 17  28
 \                  \                  \             / \
  8                  8                  8           1   8
代码示例

插入的时间复杂度:O(logn)

const insert = (root, value) => {
  const newNode = { val: value, left: null, right: null }
  if (!root) {
    return newNode
  }
  let node = root
  while(node) {
    if (value > node.val) {
      if (!node.right) {
        node.right = newNode
        return
      } else {
        node = node.right
      }
    } else {
      if (!node.left) {
        node.left = newNode
        return
      } else {
        node = node.left
      }
    }
  }
  return root
}

二叉搜索树删除

删除节点node 流程:

  1. 叶子节点,直接删除,把node的parent对于node的指向置空
  2. 只有一个子节点child,则删除node,然后把子节点child作为新的跟节点,即把node的parent对于node的指向改为child
      1                     1                       1
     /   ==> 删除节点2 ==> /   ==> 节点3替换 ==>   /
    2                     x                       3
   /                    /                        / \
  3                    3                        4   5
 / \                 /  \
4   5               4   5
  1. 删除的节点有左节点和右节点,则删除节点node,然后node的左子树的最大值,就是node的左子树的最右子节点pNode(一路向右),然后把pNode的值作为node的新值,删除的转移成删除pNode
      15                                                 15
     / \                                                / \
    9  23                                              9  23
   / \      ===> 删除节点9 ===> 找到左子树最大值4 ==> / \      ===> 
  3 12 17                                            3  12 17
 / \                                                / \
1   4                                              1  (4)

==> 替换9变成4,然后删除4
      15
     /  \
    4   23
   / \
  3  12 17
 / \
1
代码示例

删除的时间复杂度:O(logn)

const del = (root, value) => {
  let parent = null
  let node = root
  while(node && node.val !== value) {
    parent = node
    if (value > node.val) {
      node = node.right
    } else {
      node = node.left
    }
  }
  // 未找到节点
  if (!node) {
    return root
  }
  // 左右子树都存在的节点,需要找到左子树中最右的节点
  // 将最右节点的值替换到node上,然后删除的节点则转移成了,最右节点
  if (node.left && node.right) {
    // 缓存节点,由于值处理
    const temp = node
    // 变量修改
    parent = node
    // 从node的左子树开始找
    node = node.left
    while(node.right) {
      parent = node
      node = node.right
    }
    // 找到了,值进行替换
    temp.val = node.val
  }
  // 因为上面找到的最右节点一定是一个右节点为空的节点,因此可以进行下面的判断

  // 对于只有一个子节点的情况,删除的时候
  // 只需要把存在的子节点替换父节点即可,此处是直接替换,不是值替换

  // 对于叶子节点的删除,只需要父节点删除对于的子节点即可,此时child = null
  const child = node.left || node.right

  // 如果是根节点,并且没有左子树或者右子树,那直接左子树/右子树
  if (!parent) {
    return child
  }
  if (parent.left === node) {
    parent.node = child
  } else {
    parent.right = child
  }
}

二叉搜索树的查找

查找流程:

  1. 从根节点开始比较,大于则往右子树查找,小于往左子树查找
代码示例

查找的平均时间复杂度是树高 O(logn)

const find = (root, target) => {
  let node = root
  while(node && node.val !== target) {
    if (target > node.val) {
      node = node.right
    } else {
      node = node.left
    }
  }
  return !!(node && node.val === target)
}

最佳二叉搜索树

二叉搜索树查找的时间复杂度是树高,平均复杂度是O(logn),但是当最大值或者最小值作为树根的时候,树的高度会变成n,远大于平均复杂度,因此尽可能的平均左右子树的节点树,可以有效的降低树高。

让中位数做树的根节点

代码实现从1~n的节点构建一个最佳二叉树
const createBestBinarySearchTree = (start, end) => {
  if (start > end) {
    return null
  }
  const mid = Math.floor((start + end) / 2)
  const root = { val: mid, left: null, right: null }
  root.left = createBestBinarySearchTree(start, mid - 1)
  root.right = createBestBinarySearchTree(mid + 1, end)
  return root
}

平衡二叉搜索树

对于最佳二叉搜索树进行多次的插入和删除后,会变成非最佳二叉排序树,因为随着插入和删除,树根可能不是中位数了,相最大/最小偏移,影响查找速度,因此要动态的保持查找效率,需要利用平衡二叉树,也就是平衡二叉搜索树