【数据结构】二叉搜索树

目录

二叉搜索树

二叉搜索树不是空树就包含以下性质:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值。
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值。
  • 它的左右子树也分别为二叉搜索树。

也就是说根节点左边比根节点小右边比根节点大。

二叉搜索树的模拟实现

一般实现的二叉搜索树中都不含有相同值的节点。

接口实现

实现的接口(成员方法)如下:

java 复制代码
public class BinarySearchTree {
    // 插入一个元素
    public boolean insert(int key) {}
    //查找key是否存在
    public TreeNode search(int key) {}
    //删除key的值
    public boolean remove(int key) {}
}

成员变量

我们使用内部类来表示二叉树的每一个节点。并定义出来根节点。

java 复制代码
static class TreeNode {
        public int key;
        public TreeNode left;
        public TreeNode right;
        TreeNode(int key) {
            this.key = key;
        }
    }
    public TreeNode root;

插入一个元素

逻辑就是插入一个元素总能在空节点位置找到该插入的位置。

就是下图中由黑线连接的空节点。

实现思路:

  1. 如果当前树为空则插入节点为根节点。
  2. 依次向下找到该插入的位置,同时要获得该位置的父亲节点。
  3. 最后插入。

注意:**一般实现的二叉搜索树中都不含有相同值的节点。**所以插入已有元素是不会成功的。

java 复制代码
	// 插入一个元素
	public boolean insert(int key) {
        TreeNode node = new TreeNode(key);
        if(root == null) root = node;
        TreeNode pre = null;
        TreeNode cur = root;
        
        while (cur != null){
            if(cur.key == key) {
                return false;
            } else if(cur.key > key) {
                pre = cur;
                cur = cur.left;
            } else {
                pre = cur;
                cur = cur.right;
            }
        }
        if(pre.key > key) pre.left = node;
        if(pre.key < key) pre.right = node;
        return true;
    }

查找key是否存在

逻辑与二分查找类似。

代码实现思路:

  1. 当前节点等于key,返回当前节点。
  2. 当前节点比key大就去左子树找。
  3. 当前节点比key小就去右子树找。
  4. 都没找到返回空。
java 复制代码
//查找key是否存在
    public TreeNode search(int key) {
        TreeNode cur = root;
        while(cur != null) {
            if(cur.key == key) return cur;
            if(cur.key < key) cur = cur.right;
            if(cur.key > key) cur = cur.left;
        }
        return null;
    }

查询分析:

最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:logN。

最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N / 2。

删除key的值

实现思路:

  1. 设待删除结点为 cur, 待删除结点的双亲结点为 pre。

  2. cur.left == null:

    1) cur 是 root,则 root = cur.right,

    2)cur 不是 root,cur 是 parent.left,则 parent.left = cur.right,

    3)cur 不是 root,cur 是 parent.right,则 parent.right = cur.right。

  3. cur.right == null:

    1) cur 是 root,则 root = cur.left,

    2)cur 不是 root,cur 是 parent.left,则 parent.left = cur.left,

    3)cur 不是 root,cur 是 parent.right,则 parent.right = cur.left。

  4. cur.left != null && cur.right != null:

    两个思路:在左子树找最大值进行替换,右子树找最小值进行替换。

java 复制代码
//删除key的值
    public boolean remove(int key) {
        TreeNode node = new TreeNode(key);
        if(root == null) throw new NullPointerException();
        TreeNode pre = null;
        TreeNode cur = root;

        while (cur != null){
            if(cur.key == key) {
                removeNode(cur,pre);
                return true;
            } else if(cur.key > key) {
                pre = cur;
                cur = cur.left;
            } else {
                pre = cur;
                cur = cur.right;
            }
        }
        return false;
    }

    private void removeNode(TreeNode cur, TreeNode pre) {
        if(cur.left == null) {
          if(cur == root) {
              root = cur.right;
          } else if(cur == pre.right) {
              pre.right = cur.right;
          } else {
              pre.left = cur.right;
          }
        } else if(cur.right == null) {
            if(cur == root) {
                root = cur.left;
            } else if(cur == pre.right) {
                pre.right = cur.left;
            } else {
                pre.left = cur.left;
            }
        } else {
            //找到右树最小值替换
            TreeNode target = cur;
            pre =  cur;
           cur = cur.right;
           while (cur.left != null) {
               pre = cur;
               cur = cur.left;
           }
           //排除待删除节点左子树为空
           if(pre.right == cur) {
               pre = cur;
               return;
           }
           target.key = cur.key;
           cur = null;
        }
    }

TreeMap 和 TreeSet 即 java 中利用搜索树实现的 Map 和 Set;实际上用的是红黑树,而红黑树是一棵近似平衡的二叉搜索树,即在二叉搜索树的基础之上 + 颜色以及红黑树性质验证。

练习

二叉搜索树与双向链表

题目描述:

题解

解题思路:

要有一个前驱pre节点。 递归到上一级的时候 当前的根节点(pRootOfTree)就是pre的后继。

按中序遍历来遍历二叉搜索树即可。

java 复制代码
public class Solution {
    TreeNode pre = null;
    TreeNode head = null;
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree ==null) return null;
        Convert(pRootOfTree.left);
        if(head == null) {
            head = pRootOfTree;
        }
        if(pre != null) {
            pRootOfTree.left=pre;
            pre.right=pRootOfTree;
        }
        pre=pRootOfTree;
        Convert(pRootOfTree.right);
        return head;
    }
}
相关推荐
zquwei13 分钟前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring
别NULL15 分钟前
机试题——疯长的草
数据结构·c++·算法
TT哇19 分钟前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
火烧屁屁啦42 分钟前
【JavaEE进阶】初始Spring Web MVC
java·spring·java-ee
w_31234541 小时前
自定义一个maven骨架 | 最佳实践
java·maven·intellij-idea
岁岁岁平安1 小时前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA1 小时前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
Q_19284999061 小时前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
张国荣家的弟弟1 小时前
【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?
java·jar·bi
ZSYP-S2 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring