BST树(二叉搜索树、二叉排序树)

BST树(二叉搜索树、二叉排序树)

BST树概念

  1. 什么是BST树

    一棵空树或者是具有下列性质的二叉树:

    ​ 每个结点都有一个作为搜索依据的关键码( key ) ,所有结点的关键码互不相同

    ​ 左子树(如果存在)上所有结点的关健码都小于根结点的关键码

    ​ 右子树(如果存在)上所有结点的关键码都大于根结点的关键码

    ​ 左子树和右子树也是二叉搜索树

    示例:

    在这里插入图片描述

  2. 特点:中序遍历树可以得到一个递增的排序序列

  3. 注意:二叉排序树与大小根堆不同

    1. 大根堆特点:根节点大于左右孩子节点,左右子树以此类推
    2. 小根堆特点:根节点大于左右孩子节点,左右子树以此类推
    3. 二叉排序树:根节点大于左孩子节点小于右孩子节点,左右子树以此类推

BST树节点结构

static class BSTNode{
        int key;
        BSTNode leftchild;
        BSTNode parent;
        BSTNode rightchild;

        public BSTNode() {
        }

        public BSTNode(int key) {
            this.key = key;
            leftchild = null;
            parent = null;
            rightchild = null;
        }

        public BSTNode(int key, BSTNode leftchild, BSTNode parent, BSTNode rightchild) {
            this.key = key;
            this.leftchild = leftchild;
            this.parent = parent;
            this.rightchild = rightchild;
        }
    }

BST树实现

  1. 查找节点

    1. 非递归查找

      public boolean findValue(int val){
              cur = root;
              boolean flag = false;
              while (cur != null && cur.key != val){
                  cur = cur.key > val ? cur.leftchild : cur.rightchild;
              }
              if(cur != null && cur.key == val){
                  flag = true;
              }
              return flag;
          }
      
    2. 递归查找

      public boolean curFindValue(int val,BSTNode ptr){
              if (ptr == null){
                  return false;
              }
              if(ptr.key == val){
                  return true;
              }else if(ptr.key > val){
                  return curFindValue(val,ptr.leftchild);
              }else {
                  return curFindValue(val,ptr.rightchild);
              }
          }
      
  2. 插入节点

    1. 插入思路:插入分为两种情况,第一种非常简单就是当树为空的时候,new根节点就可以完成,第二种就是树不为空的时候,就需要先找到插入位置,在找的时候还需要去判断要插入的节点在树中是否存在,如果存在则插入失败,找到位置后进行插入操作。要注意的就是插入是挂到树叶子节点上,那么在插入时要保存要插入位置的双亲节点,示例如图:要将6插入就需要将6挂在5的右孩子节点

      image-20210419004739277
    2. 代码实现

      public boolean insert(int val){
              if(isEmpty()){ //树为空的插入
                  root = new BSTNode(val);
                  root.parent = null;
                  return true;
              }else {
                  cur = root;
                  BSTNode temp = cur;
                  //找到插入位置
                  while (cur != null){
                      temp = cur;
                      //在树中有此节点时则插入失败
                      if(cur.key == val){
                          return false;
                      }
                      cur = cur.key > val ? cur.leftchild : cur.rightchild;
                  }
                  //进行插入
                  if(val < temp.key){
                      temp.leftchild = new BSTNode(val);
                      temp.leftchild.parent = temp;
                  }else {
                      temp.rightchild = new BSTNode(val);
                      temp.rightchild.parent = temp;
                  }
              }
              return true;
          }
      
  3. 树的中序遍历(非递归实现)

    public boolean isBSTree(){
            int temp = Integer.MIN_VALUE;
            if(isEmpty()){
                return true;
            }
            Stack<BSTNode> stack = new Stack<>();
            cur = root;
            while (cur != null || !stack.isEmpty()){
                while (cur != null){
                    stack.push(cur);
                    cur = cur.leftchild;
                }
                cur = stack.pop();
                if(cur.key < temp){
                    return false;
                }else{
                    temp = cur.key;
                }
                cur = cur.rightchild;
            }
            return true;
        }
    
  4. 判断树是否是BST树

    1. 思路:利用BST树的中序遍历特点,如果遍历时有两个相邻的值不递增说明当前树不是BST树

    2. 代码实现:

      public boolean isBSTree(){
          	//记录上一个遍历的节点,和当前节点比较
              int temp = Integer.MIN_VALUE;
              if(isEmpty()){
                  return true;
              }
              Stack<BSTNode> stack = new Stack<>();
              cur = root;
              while (cur != null || !stack.isEmpty()){
                  while (cur != null){
                      stack.push(cur);
                      cur = cur.leftchild;
                  }
                  cur = stack.pop();
                  if(cur.key < temp){
                      return false;
                  }else{
                      temp = cur.key;
                  }
                  cur = cur.rightchild;
              }
              return true;
          }
      
  5. 删除节点

    1. 思路:

      1. 树为空时不删除

      2. 找不到删除节点时不删除

      3. 存在删除节点分为两种情况

        1. 删除的节点为双分支节点

          找到删除节点的直接后继节点,交换节点,转换为第二种情况(删除单分支节点或叶子节点)

          在这里插入图片描述

        2. 删除的节点为单分支节点或叶子节点

          1. 删除节点为普通节点:找到要删除节点的孩子节点,将孩子节点直接连接在删除节点的双亲节点上
          2. 删除节点为根节点:找到要删除节点的孩子节点,将孩子节点修改为根节点
    2. 代码:

      public boolean removeNode(int val){
              //树为空 || 树中无此节点
              if(isEmpty() || !findValue(val)){
                  return false;
              }
              //找到要删除的节点
              BSTNode temp = getNode(val);
              if(temp == null){
                  return false;
              }
              BSTNode parent = temp.parent;
              //删除节点为双分支节点,将删除双分支节点转为删除叶子节点
              if(temp.leftchild != null && temp.rightchild != null){
                  BSTNode next = Next(temp.rightchild);
                  temp.key = next.key;
                  parent = next.parent;
                  temp = next;
              }
              //删除的节点为单分支节点
              BSTNode child = temp.leftchild != null ? temp.leftchild : temp.rightchild;
              if(child != null){
                  child.parent = parent;
              }
              if(parent == null){ //删除的节点为根节点
                  root = child;
              }else{
                  if(temp.key < parent.key){
                      parent.leftchild = child;
                  }else{
                      parent.rightchild = child;
                  }
              }
              return true;
          }
      
      	private BSTNode Next(BSTNode ptr) {
              while (ptr != null && ptr.leftchild != null){
                  ptr = ptr.leftchild;
              }
              return ptr;
          }
      
  6. 使用parent域对树中序遍历(从小到大)

    	private BSTNode first(BSTNode ptr){
            while (ptr != null && ptr.leftchild != null){
                ptr = ptr.leftchild;
            }
            return ptr;
        }
    
        private BSTNode next(BSTNode ptr){
            if(ptr == null){
                return ptr;
            }
            if(ptr.rightchild != null){
                return first(ptr.rightchild);
            }else{
                BSTNode pa = ptr.parent;
                while (pa != null && pa.leftchild != ptr){
                    ptr = pa;
                    pa = ptr.parent;
                }
                return pa;
            }
        }
    
        public void NiceInOrder(){
            if(isEmpty()){
                return;
            }
            for (BSTNode ptr = first(root);ptr != null;ptr = next(ptr)){
                System.out.print(ptr.key + " ");
            }
            System.out.println();
        }
    
  7. 使用parent域对树中序遍历(从大到小)

    private BSTNode last(BSTNode ptr){
            while (ptr != null && ptr.rightchild != null){
                ptr = ptr.rightchild;
            }
            return ptr;
        }
    
        private BSTNode prev(BSTNode ptr){
            if(ptr == null){
                 return ptr;
            }
            if(ptr.leftchild != null){
                return last(ptr.leftchild);
            }else{
                BSTNode pa = ptr.parent;
                while (pa != null && pa.rightchild != ptr){
                    ptr = pa;
                    pa = ptr.parent;
                }
                return pa;
            }
        }
    
        public void resNiceInOrder(){
            if(isEmpty()){
                return;
            }
            for (BSTNode ptr = last(root);ptr != null;ptr = prev(ptr)){
                System.out.print(ptr.key + " ");
            }
            System.out.println();
        }
    
  8. 二叉搜索树转双向链表(非递归)

    public void bstreeToLinkedList(){
            if(root == null){
                return;
            }
            Stack<BSTNode> stack = new Stack<>();
            BSTNode cur = root;
            BSTNode pre = null;
            while (cur != null || !stack.isEmpty()){
                while (cur != null){
                    stack.push(cur);
                    cur = cur.leftchild;
                }
                cur = stack.pop();
                if(pre == null){
                    root = cur;
                }else{
                    pre.rightchild = cur;
                    cur.leftchild = pre;
                }
                pre = cur;
                cur = cur.rightchild;
            }
        }
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值