二叉查找树速通攻略 图文代码精心编写(Java实现)
说在前面
如题目所言
这篇文章为了给下一篇二叉查找数做铺垫和前期知识准备,以便大家有良好的阅读体验,本来想合在一起的,但觉得有些长,所以就拆开了哈哈哈,还是新手向,两篇文章有些长,但如果能认真看下去,实操踩一遍,我认为新手对二叉树的代码实现和基础知识这块,就没什么问题了。当然如果有大佬赐教留言则洗耳恭听哈哈。
符号表
含义
是一个键和一个值联系起来是它的目的,用例可以插入一对键值入表,也可以按键索值,可以按照地图去理解:键就是坐标,地点就是value,概念很简单
分类
有序;无序 ,他们的区别可以暂时粗略认为他们的key前者可以比较,后者则不可
符号表实现方式&二叉查找树的引出
- 链表,数组都可以,前者的实现具有不错的插入性能表现;后者更易于查找,有下标嘛因为,链表的话只能从头遍历,耗时完全取决于输入的目标查找和链表已有长度(计算机硬件性能就不再讨论范围了哈)。
- 但是这两种在面对海量查找和巨大符号表时候,表现糟糕,所以人们就把链表的插入优势和数组的结合,发明了二叉差查找树的数据结构。
好既然说到了树,简单把树的分类大致一说
树tree
- 定义
一种抽象数据结构 - 特点
1.有限节点
2.分层
3.节点之间用链接连接
4.几个术语:度、叶子节点、根结单、父节点、深度高度.....
基本见名知意,个别有不了解的读者可自行百度 - 分类
1.二叉树 :
图我画的有些丑大家看个意思,懂我说啥就行哈
满二叉树:简单理解就是没有空链接,所以满二叉树一定是完全二叉树
完全二叉树:最后一层从左到右的叶子结点一定要连续,中间不能有空余
第一种:
第二种
但是下面这个就不是完全二叉树,因为最下面一层从左到右叶子节点不连续
2.动态查找树:
二叉查找数(二叉树的衍生品);平衡二叉查找数(2-3树 ,红黑树);哈夫曼树
这些就是我下一篇重点和大家聊的
3.多路查找数 B树;B+树;B* 树 ,R树(这些就属于‘图’了)
二叉树之二叉查找树
好现在回来,符号表就是二叉树这些东西的预备知识,下面聊二叉查找树
下面的图从左到右表示各种树之间的一种递进关系,或者说右边的是由左边的改造增强而来,并不是包含关系
二叉树
- 基本构成元素:
1.结点,每个节点包含一个键key一个值value,每个节点都只有左右两个链接;分别指向左右节点。
2.链接(允许空链接,单不允许为空键),每个链接都指向一个独立的二叉树
二叉查找树
描述
在二叉树的基础上让键有序允许空键,各子树和他们的父节点的键之间的关系:每个节点的键都大于它左子树任意节点的键而小于右子树任意节点的键
代码实现 ,注释写的很明白,就不过多废话了
点击查看代码
package Tree;
/**
* @author HuiJixu
* @version 2.0
* @since 2021.9
*/
public class BST<Key extends Comparable<Key> ,Value>{
//BST's root node
private Node root;
//定义节点的结构
private class Node{
private Key key ;
private Value value ;
private Node left ,right ; //指向该节点的子树的左右链接
private int N ; //该接待你所包含的节点数目
//节点构造器
public Node(Key key , Value value , int N){
this.key = key ;
this.value = value ;
this.N = N;
}
public int size(){return size(root) ;}
public int size(Node x ){
if (x == null){
return 0 ;
}else{
return x.N;
}
}
//按键索值
//这个方法是暴露给用例的方法
public Value get(Key key){
return get(root , key);
}
//像这种不暴露给用例的方法就要做个封装
private Value get(Node node, Key key){
//在以root为根节点的树中查找并返回key对应的值,没有就null
if (node == null ) return null ;
//不为空就比较,类似二分法查找
int temp = key.compareTo(node.key);
if ( temp < 0 ) return get(node.left,key); //将当前节点的左子节点作为新根节点继续往下查找
else if( temp > 0 ) return get(right.right,key); //将右子树根节点作为新根节点
else return node.value;
}
public void put(Key key , Value value){
//先查找key,有key则更新,没有就新建节点
root = put( root , key ,value );
}
private Node put(Node node, Key key , Value value ){
//找不到key说明是新键,那就new 并插入该子树中
if(node == null) return new Node(key,value,1) ; //最新的叶子节点只含所有自己一个节点
//key存在在以当前node为根节点的子树中,就更新它的值
int temp = key.compareTo(node.key);
if( temp < 0 ) node.left = put(node.left ,key ,value );
else if( temp > 0 ) node.right = put(node.right ,key , value ) ;
else node.value = value ;
//更新所含有的节点数目
node.N = size(node.left) + size(node.right) + 1 ;
return node;
}
//delete() 单独说这个方法先把代码放在这里
public void delete(Key key){
root = delete(root ,key);
}
//在delete操作中,要找出右子树中的最小键对应的value ,并将其作为新的根节点,而作为原先地方的节点就要珊瑚了
public void deleteMin(){
root = deleteMin(root);
}
public Node deleteMin(Node node){
//不断检索左子树,直到遇见空节点,则说明该节点就位最小的
if ( node.left == null) return node.right;
//不是空的话就继续递归查找左子树
node.left = deleteMin(node.left);
//更新节点
node.N = size(node.right)+ size(node.left) + 1 ;
return node;
}
private Node delete(Node node , Key key ){
//空的就直接返回
if (node == null) return null ;
//二分查找非空 .递归查找
int temp = key.compareTo(node.key);
if( temp < 0 ) node.left = delete(node.left , key);
else if( temp > 0 ) node.right = delete(node , key);
//找到了就删除
else {
//下一个是空的返回另一边
if( node.left == null) return node.right ;
else if ( node.right == null) return node.right ;
//两边都不为空
Node t = node ; // 保存指向即将被删除的节点的链接
t = min(node.right); //将该链接重新指向要被删除的节点的后继节点(下文解释后继节点)
node.right = deleteMin(t.right); //将要被删除的节点指向删除后仍然所有节点都大于node.key的 //子二叉树,保证树的有序性不变
node.left = t.left ; // 左链接保持一致
}
//更新删除后节点所含有子节点数
node.N = size(node.left) + size(node.right) + 1 ;
return node ;
}
//返回最小值的节点的键
// 其实这样的话如果root节点过高的话,查询效率会首先与树的深度
public Key min(){
return min(root).key;
}
private Node min(Node node){
if (node.left == null) return node ;
return min(node.left) ;
}
}
}
二叉查找树的delete()方法
- 分析
为了方便叙述,我们约定被删除的节点记为node ,其左节点为node.left ; 右节点为node.right ,记指向node的链接为t
要删除一个节点,三件事:1.删除node 2. 将被node的左右子树父节点更新 3.更新该树的相关路径上的节点所包含的子节点个数
把1和2和起来考虑其实就是把node留下的坑填上,有两个方法一种思路:method1:在左子树找出最大的前置节点;method2:在右子树中找出最小后置节点。两者都是为了保持树的有序性。这里代码选择method1,那么就需要一个找出最小节并将其在原位置删除并且返回该最小节点的方法,实现思路就是一直沿着左子树找直到null;代码在上面名为deleteMin(Node node)。 - 实现步骤 ,我图画的是丑了写,但是意思到了哈
初始状态
1、保存指向 node 链接 t
2、将node 指向它的后继节点
3、将node的右链接指向删除后仍然都大于node.key的子二叉树
4、将node的左链接设为 t.left
整理不易,觉得还不错不妨点个赞在走嗷!
平衡二叉查找树在下一篇文章
二叉查找树速通攻略 图文代码精心编写(Java实现)的更多相关文章
- 2015最新iherb海淘攻略-图文入门教程
IHerb是美国最热门的海淘海购网站之中的一个,适合不爱担心,怕麻烦的朋友入门海淘,由于它有中文页面,可直邮中国,上千个母婴用品.化妆品.保健品品牌,最重要的是!首次下单,价值$40及以上的订单会马上 ...
- 2015最新iherb海淘攻略-图文入门教程-6月免邮
注:仅仅有首次下单才享有新人优惠10$,大家下单之后千万不要取消后.否则之后则不享有新人优惠. 注:眼下Sino-海淘客国际物流已取消,仅有UCS合众速递. IHerb是美国最热门的海淘海购网站之中的 ...
- Stick hero "攻略", android 代码编写与分析(后台截屏, 后台模拟点击)
论文写完,感觉头脑好久没被灵感刺激了,前些天室友介绍了个小游戏,我突然来了灵感可以写的简单的android 程序实现自动运行.主要的过会为三步: 1,Android 屏幕的获取.因为安全的原因,过程比 ...
- "二分法"-"折半法"-查找算法-之通俗易懂,图文+代码详解-java编程
转自http://blog.csdn.net/nzfxx/article/details/51615439 1.特点及概念介绍 下面给大家讲解一下"二分法查找"这个java基础查找 ...
- 折半插入排序 之通俗易懂,图文+代码详解-java编程
转自http://blog.csdn.net/nzfxx/article/details/51615439 1.特点及概念介绍 下面给大家讲解一下"二分法查找"这个java基础查找 ...
- Windows英文版GitHub客户端使用操作流程图文攻略教程现没中文版
Git是一个分布式的版本控制系统,最初由Linus Torvalds编写,用作Linux内核代码的管理.作为一个程序员,我们需要掌握其用法. 作为开源代码库以及版本控制系统,Github目前拥有140 ...
- GitHub超详细图文攻略
GitHub超详细图文攻略 - Git客户端下载安装 GitHub提交修改源码工作流程 Git 分类: 转载2014-03-25 21:10 10641人阅读 评论(2) 收藏 举报 GitHubbr ...
- 【转载】Google Analytics 使用图文全攻略
转载自:Google Analytics 使用图文全攻略 最近一段时间,因为工作的需要,小励使用GA(GA是Google Analytics的简称)比较频繁,所以花时间研究了一下,从不太了解到会使用( ...
- 逗塔战争TD新人入门图文攻略
逗塔战争TD新人入门图文攻略 <逗塔战争TD>是一张基于DOTA改编的塔防TD,很多玩家都很喜欢这张图,新手玩家怎么快速上手这张图呢?这张图的玩法和基本规则并不难,下面就为大家带来新人 ...
随机推荐
- 如何获取 topic 主题的列表?
bin/kafka-topics.sh --list --zookeeper localhost:2181
- Vue手动集成less预编译器
less是一门css预处理语言,简单的说就是在css的基础上提升为可编程性的预编译器 需要在项目中安装 less ,less-loader 2个插件,语法为:npm i -D less less-lo ...
- 面试问题之计算机网络:TCP三次握手四次挥手
转载于:https://www.cnblogs.com/Andya/p/7272462.html TCP三次握手: 起初A和B都处于CLOSED关闭状态 B创建TCB,处于LISTEN收听状态,等待A ...
- @Autowired 注解有什么用?
@Autowired 可以更准确地控制应该在何处以及如何进行自动装配.此注解用于在 setter 方法,构造函数,具有任意名称或多个参数的属性或方法上自动装配bean.默认情况下,它是类型驱动的注入. ...
- 说出 5 条 IO 的最佳实践?
IO 对 Java 应用的性能非常重要.理想情况下,你不应该在你应用的关键路径上 避免 IO 操作.下面是一些你应该遵循的 Java IO 最佳实践: a)使用有缓冲区的 IO 类,而不要单独读取字节 ...
- 提高scrapy爬取效率配置
提高scrapy爬取效率配置 #增加并发: 默认scrapy开启的并发线程为32个,可以适当进行增加.在settings配置文件中修改CONCURRENT_REQUESTS = 100值为100,并发 ...
- Rust 中的数据布局-repr
repr(Rust) 首先,所有类型都有一个以字节为单位的对齐方式,一个类型的对齐方式指定了哪些地址可以用来存储该值.一个具有对齐方式n的值只能存储在n的倍数的地址上.所以对齐方式 2 意味着你必须存 ...
- 5-Pandas数据分组的函数应用(df.apply()、df.agg()和df.transform()、df.applymap())
将自己定义的或其他库的函数应用于Pandas对象,有以下3种方法: apply():逐行或逐列应用该函数 agg()和transform():聚合和转换 applymap():逐元素应用函数 一 ...
- 技能篇:linux服务性能问题排查及jvm调优思路
只要业务逻辑代码写正确,处理好业务状态在多线程的并发问题,很少会有调优方面的需求.最多就是在性能监控平台发现某些接口的调用耗时偏高,然后再发现某一SQL或第三方接口执行超时之类的.如果你是负责中间件或 ...
- 微信小程序加密数据(encryptedData)解密中的PHP代码,php7.1报错
问题描述 最近在开发微信小程序涉及到加密数据(encryptedData)的解密,用的是PHP代码,在运行后报错mcrypt_module_ xxx is deprecated,提示方法已过时了 经研 ...