二叉排序树(BST)

需求

给定数列{7,3,10,12,5,1,9},要求能够高效的完成对数据的查询和添加

思路三则

  1. 使用数组,缺点:插入和排序速度较慢

  2. 链式存储,添加较快,但查找速度慢

  3. 使用二叉排序树

基本介绍

对于二叉排序树的任何一个非叶子节点,要求左子节点的值比当前节点的值小,右子节点的值比当前节点的值大

图解

步骤

  1. 从数列取出第一个数成为根节点

  2. 取出第二个数,从根结点开始比较,大于当前节点,与右子节点比较,小于当前节点与左子节点比较

  3. 直到放到叶子节点

  4. 取出剩余的数值,重复上述步骤

建立二叉排序树

代码实现:BinarySortTree.java

package com.why.binary_sort_tree;

/**
* @Description TODO 建立二叉排序树
* @Author why
* @Date 2020/12/1 14:38
* Version 1.0
**/
public class BinarySortTreeDemo {
   public static void main(String[] args) {
       int[] arr = {7,3,10,12,5,1,9};
       BinarySortTree bst = new BinarySortTree();
       for (int i = 0; i < arr.length; i++) {
           Node node = new Node(arr[i]);
           bst.add(node);
      }
       System.out.println("中序遍历二叉排序树;");
       bst.midOrder();
  }
}

/**
* 二叉排序树
*/
class BinarySortTree{
   private Node root;

   /**
    * 添加节点
    * @param node
    */
   public void add(Node node){
       if (root == null){//直接放上
           root = node;
      }else {
           root.add(node);
      }
  }

   /**
    * 中序遍历
    */
   public void midOrder(){
       if (root != null){
           root.midOrder();
      }else {
           System.out.println("二叉排序树为空");
      }
  }
}
/**
* 节点类
*/
class Node{
   int value;
   Node left;
   Node right;

   public Node(int value) {
       this.value = value;
  }

   /**
    * 添加节点,递归形式,需满足二叉排序树的要求
    * @param node
    */
   public void add(Node node){
       if (node == null){
           return;
      }
       //判断传入的节点的值和当前子树的根节点的值的关系
       if (node.value < this.value){
           if (this.left == null){//当前节点左子节点为空
               this.left = node;
          }else {//不为空,递归向左子树添加
               this.left.add(node);
          }
      }else {
           if (this.right == null){
               this.right = node;
          }else {
               this.right.add(node);
          }
      }
  }

   /**
    * 中序遍历
    */
   public void midOrder(){
       if (left != null){
           this.left.midOrder();
      }
       System.out.println(this);
       if (this.right != null){
           this.right.midOrder();
      }
  }

   @Override
   public String toString() {
       return "Node{" +
               "value=" + value +
               '}';
  }
}

二叉排序树删除

删除的节点是叶子节点

思路

  1. 先找到要删除的节点targetNode

  2. 找到targetNode的父节点parent

  3. 确定targetNode是parent的左子节点还是右子节点

  4. 根据前面的情况对应删除

删除的节点只有一棵子树的情况

思路

  1. 先找到要删除的节点targetNode

  2. 找到targetNode的父节点parent

  3. 确定targetNode的子节点是左子节点还是右子节点

  4. 确定targetNode是parent的左子节点还是右子节点

  5. 如果targetNode有左子节点

    • targetNode是parent的左子节点 parent.left = targetNode.left

    • targetNode是parent的右子节点parent.right = tsrgetNode.left

  6. 如果targetNode有右子节点

    • targetNode是parent的左子节点parent.left = targetNode.right

    • targetNode是parent的右子节点parent.right = psrent.right

删除的节点有两颗子树

思路

  1. 先找到要删除的节点targetNode

  2. 找到targetNode的父节点parent

  3. 从targetNode的右子树找到最小的节点

  4. 用一个临时变量,将最小的节点的值保存temp

  5. 删除最小节点

  6. targetNode.value = temp.value

代码实现
package com.why.binary_sort_tree;

/**
* @Description TODO 建立二叉排序树
* @Author why
* @Date 2020/12/1 14:38
* Version 1.0
**/
public class BinarySortTreeDemo {
   public static void main(String[] args) {
       int[] arr = {7,3,10,12,5,1,9,0,2,4,6,8,};
       BinarySortTree bst = new BinarySortTree();
       for (int i = 0; i < arr.length; i++) {
           Node node = new Node(arr[i]);
           bst.add(node);
      }
       System.out.println("中序遍历二叉排序树;");
       bst.midOrder();

       System.out.println("删除后");
       bst.deleteNode(5);
       bst.midOrder();

  }
}

/**
* 二叉排序树
*/
class BinarySortTree{
   private Node root;

   /**
    * 添加节点
    * @param node
    */
   public void add(Node node){
       if (root == null){//直接放上
           root = node;
      }else {
           root.add(node);
      }
  }

   /**
    * 中序遍历
    */
   public void midOrder(){
       if (root != null){
           root.midOrder();
      }else {
           System.out.println("二叉排序树为空");
      }
  }

   /**
    * 查找需删除的节点
    * @param value
    * @return
    */
   public Node search(int value){
       if (root == null){
           return null;
      }else {
           return root.search(value);
      }
  }

   /**
    * 查找父节点
    * @param value
    * @return
    */
   public Node searchParent(int value){
       if (root == null){
           return null;
      }else {
           return root.searchParent(value);
      }
  }

   public void deleteNode(int value){
       if (root == null){
           return;
      }else {
           //找到需删除的节点
           Node targetNode = search(value);
           if (targetNode == null){//未找到
               return;
          }
           //如果二叉排序树只有一个节点
           if (root.left == null && root.right == null){
               return;
          }

           //查找需删除的节点的父节点
           Node parent = searchParent(value);
           if (targetNode.left == null && targetNode.right == null){//删除的节点是叶子节点
               //判断targetNode是父节点的左子节点还是右子节点
               if (parent.left != null && parent.left.value == value){//是左子节点
                   parent.left = null;
              }else if (parent.right != null && parent.right.value == value){//是右子节点
                   parent.right = null;
              }
          }else if ((targetNode.left != null && targetNode.right == null) ||
                  (targetNode.right != null && targetNode.left == null)) {//只有一棵子树
                   //确定targetNode的节点是左节点还是右节点
                   if (targetNode.left != null) {//左子节点
                       if (parent != null){//非根节点
                           //确定targetNode是parent的左子节点还是右子节点
                           if (parent.left.value == value) {//左子节点
                               parent.left = targetNode.left;
                          } else {//右子节点
                               parent.right = targetNode.left;
                          }
                      }else {
                           root = targetNode.left;
                      }
                  } else {//右子节点
                       if (parent != null){
                           //确定targetNode是parent的左子节点还是右子节点
                           if (parent.left.value == value) {//左子节点
                               parent.left = targetNode.right;
                          } else {//右子节点
                               parent.right = targetNode.right;
                          }
                      }else {
                           root = targetNode.right;
                      }
                  }
          }else {//删除的节点有两颗子树
               //找到最小值并删除
               int minValue = deleteRightMin(targetNode.right);
               //将最小值赋值给targetNode.value
               targetNode.value = minValue;
          }
      }
  }

   /**
    * 寻找最小值
    * @param node
    * @return
    */
   public int deleteRightMin(Node node){
       Node target = node;
       while (target.left != null){
           target = target.left;
      }
       //这时target指向最小节点
       //删除最小节点
       deleteNode(target.value);
       //返回最小节点的value
       return target.value;
  }
}
/**
* 节点类
*/
class Node{
   int value;
   Node left;
   Node right;

   public Node(int value) {
       this.value = value;
  }

   /**
    * 添加节点,递归形式,需满足二叉排序树的要求
    * @param node
    */
   public void add(Node node){
       if (node == null){
           return;
      }
       //判断传入的节点的值和当前子树的根节点的值的关系
       if (node.value < this.value){
           if (this.left == null){//当前节点左子节点为空
               this.left = node;
          }else {//不为空,递归向左子树添加
               this.left.add(node);
          }
      }else {
           if (this.right == null){
               this.right = node;
          }else {
               this.right.add(node);
          }
      }
  }

   /**
    * 中序遍历
    */
   public void midOrder(){
       if (left != null){
           this.left.midOrder();
      }
       System.out.println(this);
       if (this.right != null){
           this.right.midOrder();
      }
  }

   @Override
   public String toString() {
       return "Node{" +
               "value=" + value +
               '}';
  }

   /**
    * 寻找需要删除的节点
    * @param value
    * @return
    */
   public Node search(int value){
       if (value == this.value){//找到
           return this;
      }else if (value < this.value){//向左子树查找
           if (this.left == null){
               return null;
          }
           return this.left.search(value);
      }else {//向右子树查找
           if (this.right == null){
               return null;
          }
           return this.right.search(value);
      }
  }

   /**
    * 查找需要删除节点的父节点
    * @param value
    * @return
    */
   public Node searchParent(int value){
       if ((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)){
           //找到父节点返回当前节点
           return this;
      }else {
           //如果查找的值小于当前节点的值
           if (value < this.value && this.left != null){//左子树查找
               return this.left.searchParent(value);
          }else if (value >= this.value && this.right != null){//右子树查找
               return this.right.searchParent(value);
          }else {
               return null;//没有找到父节点
          }
      }
  }
}

Java数据结构(十三)—— 二叉排序树(BST)的更多相关文章

  1. Java数据结构和算法(五)二叉排序树(BST)

    Java数据结构和算法(五)二叉排序树(BST) 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 二叉排序树(Binary S ...

  2. 数据结构------------------二叉查找树(BST)的java实现

    数据结构------------------二叉查找树(BST)的java实现 二叉查找树(BST)是一种能够将链表插入的灵活性和有序数组查找的高效性相结合的一种数据结构.它的定义如下: 二叉查找树是 ...

  3. 一文掌握关于Java数据结构所有知识点(欢迎一起完善)

    在我们学习Java的时候,很多人会面临我不知道继续学什么或者面试会问什么的尴尬情况(我本人之前就很迷茫).所以,我决定通过这个开源平台来帮助一些有需要的人,通过下面的内容,你会掌握系统的Java学习以 ...

  4. 二叉排序树(BST)构造与应用

             二叉排序树(BST)构造与应用       本文取自<数据结构与算法>(C语言版)(第三版).出版社是清华大学出版社.       本博文作为学习资料整理. 源码是VC+ ...

  5. Java数据结构和算法(一)树

    Java数据结构和算法(一)树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 前面讲到的链表.栈和队列都是一对一的线性结构, ...

  6. Java数据结构和算法(二)树的基本操作

    Java数据结构和算法(二)树的基本操作 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 一.树的遍历 二叉树遍历分为:前序遍 ...

  7. Java数据结构和算法(七)--AVL树

    在上篇博客中,学习了二分搜索树:Java数据结构和算法(六)--二叉树,但是二分搜索树本身存在一个问题: 如果现在插入的数据为1,2,3,4,5,6,这样有序的数据,或者是逆序 这种情况下的二分搜索树 ...

  8. 【java 数据结构】还不会二叉树?一篇搞定二叉树

    二叉树是我们常见的数据结构之一,在学习二叉树之前我们需要知道什么是树,什么是二叉树,本篇主要讲述了二叉树,以及二叉树的遍历. 你能get到的知识点? 1.树的介绍 2.二叉树的介绍 3.二叉树遍历的四 ...

  9. 二叉排序树(BST)创建,删除,查找操作

    binary search tree,中文翻译为二叉搜索树.二叉查找树或者二叉排序树.简称为BST 一:二叉搜索树的定义 他的定义与树的定义是类似的,也是一个递归的定义: 1.要么是一棵空树 2.如果 ...

  10. Java数据结构之队列的实现以及队列的应用之----简单生产者消费者应用

    Java数据结构之---Queue队列 队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在 ...

随机推荐

  1. [Luogu P2278] [HNOI2003]操作系统

    题面 传送门:https://www.luogu.org/problemnew/show/P2278 Solutiton 挺简单的一道模拟题,拿堆模拟一下题目意思就好 堆中有两个关键字,分别是优先级和 ...

  2. Java并发队列与容器

    [前言:无论是大数据从业人员还是Java从业人员,掌握Java高并发和多线程是必备技能之一.本文主要阐述Java并发包下的阻塞队列和并发容器,其实研读过大数据相关技术如Spark.Storm等源码的, ...

  3. 洛谷P6623——[省选联考 2020 A 卷] 树

    传送门:QAQQAQ 题意:自己看 思路:正解应该是线段树/trie树合并? 但是本蒟蒻啥也不会,就用了树上二次差分 (思路来源于https://www.luogu.com.cn/blog/dengy ...

  4. Spark编程练习题

    import org.apache.spark.sql.SparkSessionval spark = SparkSession.builder().appName("Spark SQL b ...

  5. Collection迭代器Iterator的使用

    package com.cx.Collecion; import java.util.ArrayList; import java.util.Collection; import java.util. ...

  6. 设计模式之工厂模式(Factory模式)

    在面向对象系统设计中经常遇到以下两类问题: 1)为了提高内聚(Cohesion)和松耦合(Coupling),我们经常会抽象出一些类的公共接口以形成抽象基类或者接口.这样我们可以通过声明一个指向基类的 ...

  7. 小程序·云开发地表最强CI利器来了

    小程序CI 与 CloudBase-FrameWork 从2017年开始,微信小程序的能力也随着前端的大发展的趋势越来越多,包体积限制越来越宽松,大型微信小程序的开发团队越来越多,为了适应形式,微信小 ...

  8. 系统运行后修改linux系统时区

    在网上看了很多改时间的帖子,都没能最终解决问题.最后还是下面的博客最终解决的时间的问题,感谢原作者 安装系统过程时没有选对当前的时区,即CST,Asia/Shanghai,而是按默认的,EDT时区,这 ...

  9. css子选择器 :frist-child :nth-child(n) :nth-of-type(n) ::select选择器

    记录一下前一段时间使用.学习的几种选择器. 1. :frist-child 选择器n 比如<ul><li></li> <li></li> & ...

  10. Cassandra存储附带索引(SAI)全新上线

    新一代Apache Cassandra索引现已在Astra和DataStax Enterprise 6.8.3中正式开放使用 (general availability or GA),很快您也将在开源 ...