【数据结构】二叉搜索树

目录

二叉搜索树

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

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

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

二叉搜索树的模拟实现

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

接口实现

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

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;
    }
}
相关推荐
从琳开始9899 小时前
从Socket到UDP回显服务器:Java网络编程完整指南
java·网络·网络协议·udp·java-ee
西瓜拿铁好喝9 小时前
开源和闭源 AI 办公工具,分别适合谁
java·前端·数据库
学长毕设9 小时前
基于SpringBoot的校园礼服租赁系统的设计与实现
java·spring boot·后端
明天也要努力学习10 小时前
深入理解 JVM 垃圾回收(GC)
java·jvm
golang学习记10 小时前
IDEA 断点调试技巧:拖拽
java·ide·intellij-idea
Sayai10 小时前
Flink 日志解析任务性能优化实战:正则/Grok 预编译、Guava 缓存权重陷阱与 ES 写入隔离
java·大数据·性能优化·flink·实时计算
计算机毕设定制辅导-无忧学长10 小时前
《基于物品协同过滤的闲置书换购微信小程序设计开发》
java·vue.js·spring boot·微信小程序·uniapp·闲置书换购微信小程序·物品协同过滤算法
Best_Liu~10 小时前
SpringBoot全局日期格式化
java·spring boot·后端
黎相思10 小时前
BTree
数据结构·b树·b+树
少年的范儿10 小时前
IntelliJ IDEA 配置 JDK 21 与 Maven 教程(Windows):开发环境配置与验证
java·jdk·maven·intellij idea