树——二叉搜索树

二叉搜索树

概述

  随着计算机算力的提升和对数据结构的深入研究,二叉搜索树也不断被优化和扩展,例如AVL树、红黑树等。

特性

  二叉搜索树(也称二叉排序树)是符合下面特征的二叉树:

  1.   树节点增加 key 属性,用来比较谁大谁小,key 不可以重复;
  2.   对于任意一个树节点,它的 key 比左子树的 key 都大,同时也比右子树的 key 都小。

  查找的时间复杂度与树高相关,插入、删除也是如此。

  注:

  •   二叉搜索树 - 英文 binary search tree,简称 BST
  •   二叉排序树 - 英文 binary ordered tree 或 binary sorted tree

代码

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;/*** Binary Search Tree 二叉搜索树*/
@SuppressWarnings("all")
public class BSTTree1 {BSTNode root; // 根节点static class BSTNode {int key;Object value;BSTNode left;BSTNode right;public BSTNode(int key) {this.key = key;}public BSTNode(int key, Object value) {this.key = key;this.value = value;}public BSTNode(int key, Object value, BSTNode left, BSTNode right) {this.key = key;this.value = value;this.left = left;this.right = right;}}/*** <h3>查找关键字对应的值</h3>** @param key 关键字* @return 关键字对应的值*/public Object get(int key) {BSTNode node = root;while (node != null) {if (key < node.key) {node = node.left;} else if (node.key < key) {node = node.right;} else {return node.value;}}return null;}/*** <h3>查找最小关键字对应值</h3>** @return 关键字对应的值*/public Object min() {return min(root);}private Object min(BSTNode node) {if (node == null) {return null;}BSTNode p = node;while (p.left != null) {p = p.left;}return p.value;}/*** <h3>查找最大关键字对应值</h3>** @return 关键字对应的值*/public Object max() {return max(root);}private Object max(BSTNode node) {if (node == null) {return null;}BSTNode p = node;while (p.right != null) {p = p.right;}return p.value;}/*** <h3>存储关键字和对应值</h3>** @param key   关键字* @param value 值*/public void put(int key, Object value) {root = doPut(root, key, value);}private BSTNode doPut(BSTNode node, int key, Object value) {if (node == null) {return new BSTNode(key, value);}if (key < node.key) {node.left = doPut(node.left, key, value);} else if (node.key < key) {node.right = doPut(node.right, key, value);} else {node.value = value;}return node;}/*** <h3>查找关键字的前任值</h3>** @param key 关键字* @return 前任值*/public Object predecessor(int key) {BSTNode p = root;BSTNode ancestorFromLeft = null;while (p != null) {if (key < p.key) {p = p.left;} else if (p.key < key) {ancestorFromLeft = p;p = p.right;} else {break;}}// 没找到节点if (p == null) {return null;}// 找到节点 情况1:节点有左子树,此时前任就是左子树的最大值if (p.left != null) {return max(p.left);}// 找到节点 情况2:节点没有左子树,若离它最近的、自左而来的祖先就是前任return ancestorFromLeft != null ?ancestorFromLeft.value : null;}/*** <h3>查找关键字的后任值</h3>** @param key 关键字* @return 后任值*/public Object successor(int key) {BSTNode p = root;BSTNode ancestorFromRight = null;while (p != null) {if (key < p.key) {ancestorFromRight = p;p = p.left;} else if (p.key < key) {p = p.right;} else {break;}}// 没找到节点if (p == null) {return null;}// 找到节点 情况1:节点有右子树,此时后任就是右子树的最小值if (p.right != null) {return min(p.right);}// 找到节点 情况2:节点没有右子树,若离它最近的、自右而来的祖先就是后任return ancestorFromRight != null ?ancestorFromRight.value : null;}/*** <h3>根据关键字删除</h3>** @param key 关键字* @return 被删除关键字对应值*///    public Object remove(int key) {
//        ArrayList<Object> result = new ArrayList<>(); // 保存被删除节点的值
//        root = doRemove(root, key, result);
//        return result.isEmpty() ? null : result.get(0);
//    }
//
//    /*
//              4
//             / \
//            2   6
//           /     \
//          1       7
//
//        node 起点
//        返回值 删剩下的孩子(找到) 或 null(没找到)
//     */
//    private BSTNode doRemove(BSTNode node, int key, ArrayList<Object> result) {
//        if (node == null) {
//            return null;
//        }
//        if (key < node.key) {
//            node.left = doRemove(node.left, key, result);
//            return node;
//        }
//        if (node.key < key) {
//            node.right = doRemove(node.right, key, result);
//            return node;
//        }
//        result.add(node.value);
//        if (node.left == null) { // 情况1 - 只有右孩子
//            return node.right;
//        }
//        if (node.right == null) { // 情况2 - 只有左孩子
//            return node.left;
//        }
//        BSTNode s = node.right; // 情况3 - 有两个孩子
//        while (s.left != null) {
//            s = s.left;
//        }
//        s.right = doRemove(node.right, s.key, new ArrayList<>());
//        s.left = node.left;
//        return s;
//    }public Object remove(int key) {BSTNode p = root;BSTNode parent = null;while (p != null) {if (key < p.key) {parent = p;p = p.left;} else if (p.key < key) {parent = p;p = p.right;} else {break;}}if (p == null) {return null;}// 删除操作if (p.left == null) {shift(parent, p, p.right); // 情况1} else if (p.right == null) {shift(parent, p, p.left); // 情况2} else {// 情况4// 4.1 被删除节点找后继BSTNode s = p.right;BSTNode sParent = p; // 后继父亲while (s.left != null) {sParent = s;s = s.left;}// 后继节点即为 sif (sParent != p) { // 不相邻// 4.2 删除和后继不相邻, 处理后继的后事shift(sParent, s, s.right); // 不可能有左孩子s.right = p.right;}// 4.3 后继取代被删除节点shift(parent, p, s);s.left = p.left;}return p.value;}/*** 托孤方法** @param parent  被删除节点的父亲* @param deleted 被删除节点* @param child   被顶上去的节点*/private void shift(BSTNode parent, BSTNode deleted, BSTNode child) {if (parent == null) {root = child;} else if (deleted == parent.left) {parent.left = child;} else {parent.right = child;}}/*4/   \2     6/ \   / \1   3 5   7*/// 找 < key 的所有 valuepublic List<Object> less(int key) { // key=6ArrayList<Object> result = new ArrayList<>();BSTNode p = root;LinkedList<BSTNode> stack = new LinkedList<>();while (p != null || !stack.isEmpty()) {if (p != null) {stack.push(p);p = p.left;} else {BSTNode pop = stack.pop();// 处理值if (pop.key < key) {result.add(pop.value);} else {break;}p = pop.right;}}return result;}// 找 > key 的所有 valuepublic List<Object> greater(int key) {/*ArrayList<Object> result = new ArrayList<>();BSTNode p = root;LinkedList<BSTNode> stack = new LinkedList<>();while (p != null || !stack.isEmpty()) {if (p != null) {stack.push(p);p = p.left;} else {BSTNode pop = stack.pop();// 处理值if (pop.key > key) {result.add(pop.value);}p = pop.right;}}return result;*/ArrayList<Object> result = new ArrayList<>();BSTNode p = root;LinkedList<BSTNode> stack = new LinkedList<>();while (p != null || !stack.isEmpty()) {if (p != null) {stack.push(p);p = p.right;} else {BSTNode pop = stack.pop();// 处理值if (pop.key > key) {result.add(pop.value);} else {break;}p = pop.left;}}return result;}// 找 >= key1 且 <= key2 的所有值public List<Object> between(int key1, int key2) {ArrayList<Object> result = new ArrayList<>();BSTNode p = root;LinkedList<BSTNode> stack = new LinkedList<>();while (p != null || !stack.isEmpty()) {if (p != null) {stack.push(p);p = p.left;} else {BSTNode pop = stack.pop();// 处理值if (pop.key >= key1 && pop.key <= key2) {result.add(pop.value);} else if (pop.key > key2) {break;}p = pop.right;}}return result;}}

补充

如果希望让除 int 外更多的类型能够作为 key

  •   一种方式是 key 必须实现 Comparable 接口;
  •   还有一种做法不要求 key 实现 Comparable 接口,而是在构造 Tree 时把比较规则作为 Comparator 传入,将来比较 key 大小时都调用此 Comparator 进行比较,这种做法可以参考 Java 中的 java.util.TreeMap。

前驱后继

  •   一个节点的前驱(前任)节点是指比它小的节点中,最大的那个;
  •   一个节点的后继(后任)节点是指比它大的节点中,最小的那个。

力扣题目

  1.   450. 删除二叉搜索树中的节点 
  2.   701. 二叉搜索树中的插入操作 
  3.   700. 二叉搜索树中的搜索 
  4.   98. 验证二叉搜索树 
  5.   938. 二叉搜索树的范围和
  6.   1008. 前序遍历构造二叉搜索树 
  7.   235. 二叉搜索树的最近公共祖先

来源

  数据结构与算法

路漫漫其修远兮,吾将上下而求索。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/662596.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手游反抓帧解决方案

随着游戏用户规模趋于稳定&#xff0c;游戏行业已迈入存量市场阶段&#xff0c;厂商之间的竞争愈发激烈&#xff0c;研发成本也随之激增。据数据统计&#xff1a;游戏研发成本占收入比约在 15%-35%&#xff0c;而研发成本中&#xff0c;美术资源投入占比达到了50-70%。 游戏厂商…

Java进击框架:Spring-综合(十)

Java进击框架&#xff1a;Spring-综合&#xff08;十&#xff09; 前言Rest ClientsWebClientRestTemplateHTTP接口 JMS (Java消息服务)使用Spring JMS发送消息接收消息注释驱动的侦听器端点 JMXEmail任务执行和调度Spring TaskExecutor 抽象Spring TaskScheduler 抽象支持调度…

C++算法学习心得七.贪心算法(3)

1.根据身高重建队列&#xff08;406题&#xff09; 题目描述&#xff1a; 假设有打乱顺序的一群人站成一个队列&#xff0c;数组 people 表示队列中一些人的属性&#xff08;不一定按顺序&#xff09;。每个 people[i] [hi, ki] 表示第 i 个人的身高为 hi &#xff0c;前面 …

微服务入门篇:Ribbon负载均衡(原理,均衡策略,饥饿加载)

目录 1.负载均衡原理2.负载均衡策略3.饥饿加载 1.负载均衡原理 在使用 LoadBalanced 注解后&#xff0c;Spring Cloud Ribbon 将会为 RestTemplate 添加负载均衡的能力。 负载均衡的流程如下&#xff1a; 当使用 RestTemplate 发送请求时&#xff0c;会先判断请求的 URL 是否包…

双目相机立体匹配基础

双目匹配就是用左相机和右相机去拍摄同一个点&#xff0c;目的是找到三维世界的同一个点&#xff0c;也就是在左相机和右相机中的成像点之间的像素差&#xff08;视差&#xff09;&#xff0c;根据视差去求解深度&#xff0c;那么找到左相机点到右相机的同一个对应点这个过程就…

c++设计模式之观察者模式(发布-订阅模式)

介绍 观察者模式主要关注于对象的一对多关系&#xff0c;其中多个对象都依赖于一个对象&#xff0c;当该对象的状态发生改变时&#xff0c;其余对象都能接收到相应的通知。 如&#xff0c;现在有 一个数据对象三个画图对象&#xff0c;分别wield曲线图、柱状图、饼状图三个对象…

数据结构与算法面试系列-03

1. 一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在 第10次落地时,共经过多少米?第10次反弹多高? 程序代码 package com.jingxuan.system;public class Sphere {public static void main(String[] args) {double s = 0;double t = 100;for (int i…

Qt6入门教程 15:QRadioButton

目录 一.简介 二.常用接口 三.实战演练 1.径向渐变 2.QSS贴图 3.开关效果 4.非互斥 一.简介 QRadioButton控件提供了一个带有文本标签的单选按钮。 QRadioButton是一个可以切换选中&#xff08;checked&#xff09;或未选中&#xff08;unchecked&#xff09;状态的选项…

Flink 1.18.1的基本使用

系统示例应用 /usr/local/flink-1.18.1/bin/flink run /usr/local/flies/streaming/SocketWindowWordCount.jar --port 9010nc -l 9010 asd asd sdfsf sdf sdfsdagd sdf单次统计示例工程 cd C:\Dev\IdeaProjectsmvn archetype:generate -DarchetypeGroupIdorg.apache.flink -…

maven代码规范检查(checkstyle、findbugs)

maven代码规范检查 前言一、使用checkstyle插件1. maven-checkstyle-plugin 介绍2. 接入方式3. 如何排除某个类、包下面的文件不进行检查使用suppressionsLocation 4. 如何关闭 二、使用findbugs插件1.findbugs-maven-plugin介绍2. 接入方式3. 如何排除某个类、包下面的文件不进…

TraceRoute 跟踪路由工具

随着企业网络需求的不断增长&#xff0c;组织发现监控和管理其网络基础设施变得越来越困难&#xff0c;网络管理员正在转向其他工具和资源&#xff0c;这些工具和资源可以使他们的工作更轻松一些&#xff0c;尤其是在故障排除方面。 目前&#xff0c;网络管理员主要使用简单、…

git使用以及工作中开发流程

Git是当前最先进、最主流的分布式版本控制系统&#xff0c;免费、开源。 主要概念&#xff1a; 基本流程&#xff1a; 命令&#xff1a; git commit -a # 省略了add到暂存区的步骤&#xff0c;直接提交工作区的修改内容到版本库&#xff0c;不包括新增的文件。git fetc…

myql 项目数据库和表的设计

1.表的设计和创建 2.在navicate运行这些代码 create table user(id int not null auto_increment primary key,name varchar(50) not null unique,password varchar(50) not null,state enum(online,offline) default offline ); create table friend(userid int not null,…

day37WEB攻防-通用漏洞XSS跨站权限维持钓鱼捆绑浏览器漏洞

目录 XSS-后台植入 Cookie&表单劫持&#xff08;权限维持&#xff09; 案例演示 XSS-Flash 钓鱼配合 MSF 捆绑上线 1、生成后门 2、下载官方文件-保证安装正常 3、压缩捆绑文件-解压提取运行 4、MSF 配置监听状态 5、诱使受害者访问 URL-语言要适当 XSS-浏览器网马…

Echars3D 饼图开发

关于vue echart3D 饼图开发 首先要先下载 "echarts-gl", 放在main.js npm install echarts-gl --save <template><div class"cointan"><!-- 3d环形图 --><div class"chart" id"cityGreenLand-charts"><…

03. 【Linux教程】安装虚拟机

前面小节介绍了 Linux 和 GUN 项目&#xff0c;本小节开始学习如何在 Windows 上安装虚拟机&#xff0c;虚拟机安装之后可以在虚拟机中安装 Linux 相关的操作系统&#xff0c;常见的虚拟机软件有 VirtualBox、VMware 等等&#xff0c;本教程使用 VMware 虚拟机软件来演示如何安…

java数据结构与算法刷题-----LeetCode198. 打家劫舍

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 很多人觉得动态规划很难&#xff0c;但它就是固定套路而已。其实动态规划只…

Flink CDC 3.0 详解

一、Flink CDC 概述 Flink CDC 是基于数据库日志 CDC&#xff08;Change Data Capture&#xff09;技术的实时数据集成框架&#xff0c;支持全增量一体化、无锁读取、并行读取、表结构变更自动同步、分布式架构等高级特性。配合Flink 优秀的管道能力和丰富的上下游生态&#x…

开启Android学习之旅-1

最近在学习《第一行代码 Android》&#xff0c;两天看书把所有代码都敲了一遍。由于之前没有接触过 Kotlin&#xff0c;导致了囫囵吞枣&#xff0c;跟着书会敲&#xff0c;离开就忘了。Android 大佬开发的各种框架、控件好像大部分都用了 Kotlin。看他们的源码&#xff0c;理解…

【每日一题】7.LeetCode——合并两个有序链表

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》|《数据结构与算法》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有限&#xff0c;欢…