二叉搜索树的概念以及js实现增删操作

二叉搜索树 js

1、概念

二叉搜索树又称二叉查找树、二叉排序树。它满足如下性质

  • 它的所有左子树上面的节点均比它小
  • 它的所有右子树上面的节点均比它大
  • 它的左右子树也满足二叉搜索树的性质

2、二叉搜索树的数据结构

  function TreeNode(data) {
    this.data = data; // 实际的数据
    this.lchild = null; // 左节点
    this.rchild = null; // 右节点
  }

3、二叉搜索树的操作

3.1 插入

插入的操作就是当根节点为null的时候,直接创建一个新的节点赋值给根节点;否则和根节点比较大小,比根节点大去右子树插入,比根节点小去左子树插入,循环执行直到插入成功!

  // root是根节点
  function insert(data) {
    if(root === null) {
      root = new TreeNode(data);
      return SUCCESS;
    }
    let node = root;
    while(1) {
      if(node.data === data) {
        return NODE_DATA_EXSIT;
      }
      // 值比父节点小,插入到左边
      if(node.data > data) {
        if(node.lchild === null) {
          node.lchild = new TreeNode(data);
          return SUCCESS;
        }
        node = node.lchild;
        continue;
      }
      // 值比父节点大,插入到右边
      if(node.data < data) {
        if(node.rchild === null) {
          node.rchild = new TreeNode(data);
          return SUCCESS;
        }
        node = node.rchild;
        continue;
      }
    }
  }
3.2 查找&构造

构造这里不做赘述,构造其实就是一个循环的插入过程
查找这里不做赘述,根据二叉搜索树的性质即可

3.3 删除

谈到删除我希望可以先明白一个概念:中序遍历

树是一个适合递归处理的结构(大部分场景如此),中序遍历其实就是:左子树,当前节点,右子树的顺序。其中左子树和右子树又是一个树的中序遍历,所以所中序遍历是一个特别适合用递归去操作的遍历实现

删除分为如下3种情况

  • 删除的节点没有子节点
    image
  • 删除的节点只有左节点或者右节点
    image
    image
  • 删除的节点既有左节点又有右节点
    image


假如我们要删除的节点是根节点(只是举例)。其中第一种情况很好办,只需要将根节点的父节点指向设置为空即可(不是根节点的时候将其父节点的指向设置为空即可)。第二种情况当只有左节点或者只有右节点的时候,只需要将节点的指向重新指向仅存的唯一的节点即可。我么重点需要讨论的是当左右子节点均存在的时候应该如何实现


我们刚刚说了中序遍历的过程,我们需要了解的一个性质是 根节点的前驱是一定没有右节点的


假设前驱节点是存在右节点的,那么遍历的顺序就是前驱节点、前驱节点的右节点、根节点,这样是违背了前驱节点的定义(因为我们所谓的前驱节点就应该是根节点的前一个!)


可能上述概念比较绕弯,但是一定要理解,因为前驱节点最多只有一个左节点,这样我们将前驱节点移动到根节点的位置,在将前驱节点删除即可(删除回到了问题本身,其实也是个递归,只不过这个递归肯定是2次而已)


同理,也可以将后继节点覆盖到根节点上,与前驱节点同理,这里不做赘述。

  // data是要待删除的数据
  function del(data) {
    let prev = null; // 记录查找到的节点的前驱节点
    let node = root;
    while(node) {
      if(node.data === data) { // 找到了要删除的节点
        break;
      }
      // 去左子树找
      if(node.data > data) {
        prev = node;
        node = node.lchild;
        continue;
      }
      // 去右子树找
      if(node.data < data) {
        prev = node;
        node = node.rchild;
        continue;
      }
    }

    // 没有找到待删除的节点
    if(node == null) {
      return DELETE_DATA_NOT_EXSIT;
    }

    // 删除的节点既没有左节点也没有右节点
    if(!node.lchild && !node.rchild) {
      if(prev == null) { // 根节点,这时候就把这棵树删了。。。
        root = null;
        return SUCCESS;
      }
      prev.lchild === node && (prev.lchild = null); // 是左节点就删除左节点
      prev.rchild === node && (prev.rchild = null); // 是右节点就删除右节点
      return SUCCESS;
    }
    
    // 删除的只有一个节点
    if(node.lchild && !node.rchild) { // 有左节点
      if(prev == null) {
        root = node.lchild;
        return SUCCESS;
      }
      prev.lchild === node && (prev.lchild = node.lchild); 
      prev.rchild === node && (prev.rchild = node.lchild); 
      return SUCCESS;
    }
    if(!node.lchild && node.rchild) { // 有右节点
      if(prev == null) {
        root = node.rchild;
        return SUCCESS;
      }
      prev.lchild === node && (prev.lchild = node.rchild); 
      prev.rchild === node && (prev.rchild = node.rchild); 
      return SUCCESS;
    }

    // 接下来的情况就是既有左节点又有右节点了
    let prev2 = node;
    let node2 = node.rchild;
    while(node2.rchild) { // 可以思考下这里为什么一直是rchild,如果要是取后继节点替换得话,这里还是rchild嘛,为什么?
      prev2 = node2;
      node2 = node2.rchild;
    }

    // 这个时候node2就是要替换得节点,先把数据替换了
    node.data = node2.data; // 这里执行完毕代表已经把输入得data已经删除了,那么替换得node2也要删除
    
    // prev.rchild是因为他肯定是右节点
    // node2.lchild是如果删除的node2节点有左节点就把左节点给赋值到node2的父节点对应的节点(就是上一行的右节点)
    // 没有的话就是null赋值,所以其实就是node.lchild(没有的左节点node2.lchild就是null)
    prev.rchild = node2.lchild;
    return SUCCESS;
  }

其实主要考虑到删除节点的各种情况就好了,然后分情况处理即可

上述代码是前驱节点替换,爱动手的也可以试试后继节点替换~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 二叉搜索树(BST)是一种特殊的树结构,它具有特殊的性质:每个节点的左孩子节点的值小于其父节点的值,而每个节点的右孩子节点的值大于父节点的值。查找、插入和删除节点的操作过程如下:查找节点:从根节点开始,如果要查找的值大于节点值,则向右子树查找;如果要查找的值小于节点值,则向左子树查找;直到找到要查找的值 ### 回答2: 二叉搜索树(Binary Search Tree,BST)是一种特殊的二叉树,其中每个节点的值都大于其左子树中的任何节点,同时小于其右子树中的任何节点。这个特性使得二叉搜索树在进行查找、插入和删除节点操作时效率较高。 1. 查找节点操作:从根节点开始,根据目标值与当前节点值的比较结果选择向左子树或右子树移动,直到找到目标值或者遍历到叶子节点为止。 2. 插入节点操作:与查找类似,根据目标值与当前节点值的比较结果选择向左子树或右子树移动,直到找到空位置,然后创建新节点并将其连接到该空位置。 3. 删除节点操作: - 当待删除节点没有子节点时,直接将其父节点对应的子节点指针置为空即可。 - 当待删除节点只有一个子节点时,将该子节点替代待删除节点的位置。 - 当待删除节点有两个子节点时,可以选择以其左子树中的最大节点或右子树中的最小节点进行替代,然后递归删除该最大或最小节点,以保持二叉搜索树的结构。 程序实现过程可以采用递归或迭代的方式。在递归实现中,可以通过函数的递归调用来实现节点的查找、插入和删除操作。在迭代实现中,可以利用栈或队列等数据结构来辅助节点的操作过程。 以上是对二叉搜索树概念及查找、插入和删除节点操作过程的简要介绍。实际应用中,还需要考虑一些特殊情况,并进行错误处理,以确保二叉搜索树实现正常运行。 ### 回答3: 二叉搜索树(Binary Search Tree,简称BST)是一种特殊的二叉树,它满足以下性质:对于任意节点,左子树的键值小于它的键值,右子树的键值大于它的键值。 查找节点的操作过程如下: 1. 若树为空,则返回空。 2. 若当前节点的键值与目标键值相等,则返回当前节点。 3. 若当前节点的键值大于目标键值,则继续在当前节点的左子树中进行查找。 4. 若当前节点的键值小于目标键值,则继续在当前节点的右子树中进行查找。 插入节点的操作过程如下: 1. 若树为空,则将待插入节点设为根节点。 2. 若待插入节点的键值小于当前节点的键值,则继续在当前节点的左子树中插入。 3. 若待插入节点的键值大于当前节点的键值,则继续在当前节点的右子树中插入。 删除节点的操作过程如下: 1. 若待删除节点为叶子节点,则直接删除。 2. 若待删除节点只有一个子节点,则将其子节点替换为待删除节点。 3. 若待删除节点有两个子节点,则找到它的后继节点或前驱节点来替换该节点。后继节点即右子树中最小的节点,前驱节点即左子树中最大的节点。 BST的程序实现过程如下(以Python为例): ```python class TreeNode: def __init__(self, val): self.val = val self.left = None self.right = None class BST: def __init__(self): self.root = None def search(self, target): curr = self.root while curr: if curr.val == target: return curr elif curr.val > target: curr = curr.left else: curr = curr.right return None def insert(self, val): if not self.root: self.root = TreeNode(val) return curr = self.root while curr: if curr.val > val: if not curr.left: curr.left = TreeNode(val) return else: curr = curr.left else: if not curr.right: curr.right = TreeNode(val) return else: curr = curr.right def delete(self, val): def find_min(node): while node.left: node = node.left return node def delete_node(node, target): if not node: return None if node.val > target: node.left = delete_node(node.left, target) elif node.val < target: node.right = delete_node(node.right, target) else: if not node.left and not node.right: return None elif not node.left: return node.right elif not node.right: return node.left else: successor = find_min(node.right) node.val = successor.val node.right = delete_node(node.right, successor.val) return node self.root = delete_node(self.root, val) ``` 以上代码实现二叉搜索树的插入、查找和删除操作

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值