史上最全二叉查找树详解——带详细图解

1、二叉查找树的性质与规则

        若一个结点的左子树不为空,则它左子树上所有的结点都小于该结点;若一个结点的右子树的不为空,则它右子树上所有的结点都大于该结点

2、二叉查找树的创建

a、二叉查找树的结点类

public class Node{
        public Key key;//存储键
        private Value value;//存储值
        
        public Node left;//记录左子结点
        
        public Node right;//记录右子结点
        
        public Node(Key key,Value value,Node left,Node right) {
        	this.key = key;
        	this.value = value;
        	this.left = left;
        	this.right = right;
        }
}

b、二叉查找树实现

插入方法(put)实现思想:

  •         如果当前书中没有任何一个结点,则直接把新节点当做根节点使用
  •         如果当前树不为空,则从根节点开始:
  •         如果新结点的key小于当前结点的key,则继续找当前结点的左子结点
  •         如果新结点的key大于当前结点的key,则继续找当前结点的右子结点
  •         如果新结点的key等于当前结点的key,则树中已经存在这样的结点,替换该结点的value值

流程图如下:

查询(get)实现思想:

        从根节点开始:

  •         如果要查询的key小于当前结点的key,则继续找当前结点的左子结点
  •         如果要查询的key大于当前结点的key,则继续找当前结点的右子结点
  •         如果要查询的key等于当前结点的key,则返回当前结点的value

删除方法delete实现思想:

  •         找到被删除结点
  •         找到被删除结点右子树的最小结点minNode
  •         删除右子树中的最小结点
  •         让被删除结点的左子树称为最小结点minNode的左子树,让被删除结点的右子树称为最小结点minNode的右子树
  •         让被删除结点的父节点指向最小结点minNode

完整代码



//二叉树代码
class BinaryTree<Key extends Comparable<Key>, Value> {
  //记录根结点
  private Node root;
  //记录树中元素的个数
  private int N;
  //获取树中元素的个数
  public int size() {
      return N;
  }
  //向树中添加元素key-value
  public void put(Key key, Value value) {
      root = put(root, key, value);
  }
  //向指定的树x中添加key-value,并返回添加元素后新的树
  private Node put(Node x, Key key, Value value) {
      if (x == null) {
          //个数+1
          N++;
          return new Node(key, value, null, null);
      }
      int cmp = key.compareTo(x.key);
      if (cmp > 0) {
          //新结点的key大于当前结点的key,继续找当前结点的右子结点
          x.right = put(x.right, key, value);
      } else if (cmp < 0) {
          //新结点的key小于当前结点的key,继续找当前结点的左子结点
          x.left = put(x.left, key, value);
      } else {
          //新结点的key等于当前结点的key,把当前结点的value进行替换
          x.value = value;
      }
      return x;
  }
  //查询树中指定key对应的value
  public Value get(Key key) {
      return get(root, key);
  }
  //从指定的树x中,查找key对应的值
  public Value get(Node x, Key key) {
      if (x == null) {
          return null;
      }
      int cmp = key.compareTo(x.key);
      if (cmp > 0) {
          //如果要查询的key大于当前结点的key,则继续找当前结点的右子结点;
          return get(x.right, key);
      } else if (cmp < 0) {
          //如果要查询的key小于当前结点的key,则继续找当前结点的左子结点;
          return get(x.left, key);
      } else {
          //如果要查询的key等于当前结点的key,则树中返回当前结点的value。
          return x.value;
      }
  }
  //删除树中key对应的value
  public void delete(Key key) {
      root = delete(root, key);
  }
  //删除指定树x中的key对应的value,并返回删除后的新树
  public Node delete(Node x, Key key) {
      if (x == null) {
          return null;
      }
      int cmp = key.compareTo(x.key);
      if (cmp > 0) {
          //新结点的key大于当前结点的key,继续找当前结点的右子结点
          x.right = delete(x.right, key);
      } else if (cmp < 0) {
          //新结点的key小于当前结点的key,继续找当前结点的左子结点
          x.left = delete(x.left, key);
      } else {
          //新结点的key等于当前结点的key,当前x就是要删除的结点
          //1.如果当前结点的右子树不存在,则直接返回当前结点的左子结点
          if (x.right == null) {
              return x.left;
          }
          //2.如果当前结点的左子树不存在,则直接返回当前结点的右子结点
          if (x.left == null) {
              return x.right;
          }
          //3.当前结点的左右子树都存在
          //3.1找到右子树中最小的结点
          Node minNode = x.right;
          while (minNode.left != null) {
              minNode = minNode.left;
          }
          //3.2删除右子树中最小的结点
          Node n = x.right;
          while (n.left != null) {
              if (n.left.left == null) {
                  n.left = null;
              } else {
                  n = n.left;
              }
          }
          //3.3让被删除结点的左子树称为最小结点minNode的左子树,让被删除结点的右子树称为最小结点minNode的右子树
          minNode.left = x.left;
          minNode.right = x.right;
          //3.4让被删除结点的父节点指向最小结点minNode
          x = minNode;
          //个数-1
          N--;
      }
      return x;
  }
  private class Node {
      //存储键
      public Key key;
      //存储值
      private Value value;
      //记录左子结点
      public Node left;
      //记录右子结点
      public Node right;
      public Node(Key key, Value value, Node left, Node right) {
          this.key = key;
          this.value = value;
          this.left = left;
          this.right = right;
      }
  }
}
//测试代码
public class Test {
  public static void main(String[] args) throws Exception {
      BinaryTree<Integer, String> bt = new BinaryTree<>();
      bt.put(4, "二哈");
      bt.put(1, "张三");
      bt.put(3, "李四");
      bt.put(5, "王五");
      System.out.println(bt.size());
      bt.put(1,"老三");
      System.out.println(bt.get(4));
      bt.put(2, "小屋");
      System.out.println(bt.size());
      bt.delete(2);
      System.out.println(bt.size());
  }
}

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值