Java 【数据结构】 TreeSetTreeMap(二叉搜索树详解)【神装】

登神长阶

 第八神装 TreeSet

   第九神装  TreeMap


目录

💉 一.二叉搜索树

🩸1. 定义

💊2. 基本操作

🩹3. 插入操作

🩼4. 查找操作

🩺5. 删除操作*

🩻6. 遍历操作

🪒7.性能分析

🪥二.TreeSet

🧽1. 定义

🧻 2.操作

🪣3. Set主要特性

🫧4. TreeSet的内部实现

🛒5. 应用场景

🧯三.TreeMap

🧹1.定义

🪤2.操作

🧷3.Map的主要特性

🧿4. TreeMap的内部实现

🪬5.应用场景 

🗿四.总结与反思


💉 一.二叉搜索树

首先我们要知道TreeSet/TreeMap底层都采用的都是一种二叉搜索树(也叫自平衡二叉树),因此我们先来了解一下二叉搜索树。

对于他的学习若之前没有了解的可以参考:Java 【数据结构】 二叉树(Binary_Tree)【神装】

🩸1. 定义

二叉搜索树(Binary Search Tree,简称BST),是一种特殊的二叉树,它具有以下性质:

  • 每个节点都有一个键(Key)和两个指向其他节点的指针(左子指针和右子指针)。
  • 任意节点的左子树中的所有键都小于该节点的键。
  • 任意节点的右子树中的所有键都大于该节点的键。
  • 左右子树也都是二叉搜索树。
  • 不存在键值相等的节点。

在Java中,我们可以这样定义一个二叉搜索树:

public class BinarySearchTree {private class Node {int val;Node left;Node right;Node(int val) {this.val = val;left = null;right = null;}}private Node root;// 构造函数、插入方法、查找方法、删除方法等...
}

💊2. 基本操作

二叉搜索树支持以下基本操作:

  • 插入(Insert):向树中插入一个新节点,保持树的二叉搜索性质。
  • 查找(Search):在树中查找一个特定的节点。
  • 删除(Delete):从树中删除一个节点,并保持树的二叉搜索性质。
  • 遍历(Traverse):对树进行遍历,常用的遍历方式有前序、中序和后序遍历。

接下来我们详细介绍一下它的各个操作,因为后续二叉树本身是数据结构中一个很关键的知识点,像红黑树,AVL树等等,我们需要牢牢掌握!

🩹3. 插入操作

插入操作的步骤如下:

  1. 创建新节点。
  2. 比较新节点的键与根节点的键:
    • 如果新节点的键小于根节点的键,则将新节点插入到根节点的左子树中。
    • 如果新节点的键大于根节点的键,则将新节点插入到根节点的右子树中。
  3. 如果插入点是空,则直接在新位置插入新节点。
  4. 如果插入点非空,则递归地在相应子树中进行插入操作。

代码: 

 /*** 插入一个元素* @param key*/public void insert(int key) {TreeNode node=new TreeNode(key);//若该搜索树为空,则直接作为根节点;if (root==null){root=node;}TreeNode cur=root;TreeNode parent=null;while(cur!=null){if (cur.key<key){parent = cur;cur=cur.right;}else if(cur.key>key){parent = cur;cur=cur.left;}else{return ;}}if (parent.key>key){parent.left=node;}else{parent.right=node;}}

🩼4. 查找操作

查找操作的步骤如下:

  1. 从根节点开始比较。
  2. 如果查找的键小于当前节点的键,则递归地在左子树中查找。
  3. 如果查找的键大于当前节点的键,则递归地在右子树中查找。
  4. 如果找到节点,则返回该节点。
  5. 如果没有找到,则返回null。

代码

 //查找key是否存在public TreeNode search(int key) {TreeNode cur =root;while(cur!=null){if (cur.key<key){cur=cur.right;}else if(cur.key>key){cur=cur.left;}else{return cur;}}return null;}

🩺5. 删除操作*

设待删除结点为 cur, 待删除结点的双亲结点为 parent
1. cur.left == null
  1. cur root,则 root = cur.right
  2. cur 不是 rootcur parent.left,则 parent.left = cur.right
  3. cur 不是 rootcur parent.right,则 parent.right = cur.right
2. cur.right == null
  1. cur root,则 root = cur.left
  2. cur 不是 rootcur parent.left,则 parent.left = cur.left
  3. cur 不是 rootcur parent.right,则 parent.right = cur.left
3. cur.left != null && cur.right != null
  • 需要使用替换法进行删除,即在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题

代码

//删除key的值public boolean remove(int key) {TreeNode cur =root;TreeNode parent=null;while(cur!=null){if (cur.key>key){parent=cur;cur=cur.left;}else if (cur.key<key){parent=cur;cur=cur.right;}else{removeNode(parent,cur);return true;}}return false;}public void removeNode(TreeNode parent,TreeNode cur){if (cur.left==null){//左子树为空if (cur==root){root=cur.right;}else if(cur==parent.left){parent.left=cur.right;}else{parent.right=cur.right;}}else if (cur.right==null){//右子树为空if (cur==root){root=cur.left;}else if (cur==parent.left){parent.left=cur.left;}else{parent.right=cur.left;}}else{//左右子树都不为空 右子树的最小值代替TreeNode targetp=cur;TreeNode target=cur.right;while(target!=null){targetp=target;target=target.left;}cur.key=target.key;//删除原本数值if (targetp.left==target){targetp.left=target.left;}else{targetp.right=target.right;}}}

🩻6. 遍历操作

二叉搜索树的遍历操作与普通二叉树相同,可以使用前序、中序和后序遍历。

中序遍历会按照从小到大的顺序访问所有节点,是一个有序数列

前序遍历代码举例

  public void prevOreder(TreeNode root){if (root==null){return;}prevOreder(root.left);System.out.print(root.key+" ");prevOreder(root.right);}

其余遍历方式,包括非递归的遍历方式:  Java 【数据结构】 二叉树(Binary_Tree)【神装】

🪒7.性能分析

        插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。
        但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:

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

🪥二.TreeSet

🧽1. 定义

TreeSet是Java集合框架中的一种有序集合,它实现了Set接口,因此具有不允许重复元素的特性。与HashSet不同,TreeSet使用红黑树数据结构来存储元素,这使得元素在集合中保持有序。

🧻 2.操作

方法
解释
boolean add (E e)
添加元素,但重复元素不会被添加成功
void clear ()
清空集合
boolean contains (Object o)
判断 o 是否在集合中
Iterator<E> iterator ()
返回迭代器
boolean remove (Object o)
删除集合中的 o
int size()
返回 set 中元素的个数
boolean isEmpty()
检测 set 是否为空,空返回 true ,否则返回 false
Object[] toArray()
set 中的元素转换为数组返回
boolean containsAll(Collection<?> c)
集合 c 中的元素是否在 set 中全部存在,是返回 true ,否则返回 false
boolean addAll(Collection<? extends E> c)
将集合 c 中的元素添加到 set 中,可以达到去重的效果
import java.util.TreeSet;public class TreeSetExample {public static void main(String[] args) {// 创建一个TreeSet,元素自然排序(升序)TreeSet<Integer> numbers = new TreeSet<>();// 添加一些元素numbers.add(5);numbers.add(3);numbers.add(8);numbers.add(1);// 打印整个TreeSetSystem.out.println("TreeSet: " + numbers);// 查找是否存在某个元素System.out.println("Contains 6: " + numbers.contains(6));// 删除一个元素numbers.remove(3);System.out.println("TreeSet after removing 3: " + numbers);// 遍历TreeSetSystem.out.println("Traversing TreeSet:");for (int number : numbers) {System.out.println(number);}// 排序和检索操作System.out.println("First element: " + numbers.first());System.out.println("Last element: " + numbers.last());System.out.println("Element greater than 4: " + numbers.higher(4));System.out.println("Element lower than 4: " + numbers.lower(4));}
}

🪣3. Set主要特性

  • Set是继承自Collection的一个接口类
  • TreeSet 中不能插入 null key HashSet 可以。
  • 实现 Set 接口的常用类有 TreeSet HashSet ,还有一个 LinkedHashSet LinkedHashSet 是在 HashSet 的基础上维护了一个双向链表来记录元素的插入次序。
  • 有序性:元素按照自然顺序或者根据提供的Comparator进行排序。当向TreeSet中添加元素时,会根据元素之间的比较关系进行自动排序。
  • 不可重复性:TreeSet中的元素不允许重复。Set最大的功能就是对集合中的元素进行去重
  • 基于红黑树实现:通过红黑树数据结构实现了有序的、唯一元素存储。
Set 底层结构
TreeSet
底层结构
红黑树
插入 / 删除 / 查找时间
复杂度
O(log N)
是否有序
关于 Key 有序
线程安全
不安全
插入 / 删除 / 查找区别
按照红黑树的特性来进行插入和删除
比较与覆写
key 必须能够比较,否则会抛出
ClassCastException 异常
应用场景
需要 Key 有序场景下

🫧4. TreeSet的内部实现

TreeSet通过红黑树(Red-Black Tree)数据结构实现了有序的、唯一元素存储。红黑树是一种自平衡的二叉查找树,在插入和删除操作后能够保持相对较低的高度,从而保证了检索、插入和删除操作的时间复杂度为O(log n)。

🛒5. 应用场景

TreeSet适用于需要保持元素有序并且去除重复元素的场景。由于其基于红黑树实现,可以高效地支持元素的查找、插入和删除操作。因此,在需要有序集合且不允许重复元素的情况下,TreeSet是一个十分实用的选择。总而言之:

  • 当需要保持元素的有序性且不允许重复时,TreeSet是一个很好的选择。
  • 常用于需要按照特定顺序处理元素的情况。

🧯三.TreeMap

🧹1.定义

TreeMap是基于红黑树数据结构的键值对映射。它保证键的有序性,键按照其自然顺序(通过键的compareTo方法确定的顺序)进行排序。

🪤2.操作

方法
解释
V get (Object key)
返回 key 对应的 value
V getOrDefault (Object key, V defaultValue)
返回 key 对应的 value key 不存在,返回默认值
V put (K key, V value)
设置 key 对应的 value
V remove (Object key)
删除 key 对应的映射关系
Set<K> keySet ()
返回所有 key 的不重复集合
Collection<V> values ()
返回所有 value 的可重复集合
Set<Map.Entry<K, V>> entrySet ()
返回所有的 key-value 映射关系
boolean containsKey (Object key)
判断是否包含 key
boolean containsValue (Object value)
判断是否包含 value
import java.util.Map;
import java.util.TreeMap;public class TreeMapExample {public static void main(String[] args) {// 创建一个 TreeMapTreeMap<Integer, String> treeMap = new TreeMap<>();// 向 TreeMap 中添加键值对treeMap.put(1, "value1");treeMap.put(2, "value2");treeMap.put(3, "value3");treeMap.put(4, "value4");treeMap.put(5, "value5");// 打印 TreeMapSystem.out.println("TreeMap: " + treeMap);// 获取一个键对应的值String value = treeMap.get(3);System.out.println("Value for key 3: " + value);// 删除一个键值对boolean removed = treeMap.remove(2);System.out.println("Remove key 2: " + removed);// 获取 TreeMap 的大小int size = treeMap.size();System.out.println("Size of TreeMap: " + size);// 检查 TreeMap 是否为空boolean isEmpty = treeMap.isEmpty();System.out.println("Is TreeMap empty: " + isEmpty);// 遍历 TreeMapfor (Map.Entry<Integer, String> entry : treeMap.entrySet()) {System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());}}
}

🧷3.Map的主要特性

  1. Map是一个接口,不能直接实例化对象,如果要实例化对象只能实例化其实现类TreeMap或者HashMap
  2. Map中存放键值对的Key是唯一的,value是可以重复的
  3. TreeMap中插入键值对时,key不能为空,否则就会抛NullPointerException异常value可以为空。但是HashMapkeyvalue都可以为空。
  4. Map中的Key可以全部分离出来,存储到Set来进行访问(因为Key不能重复)
  5. Map中的value可以全部分离出来,存储在Collection的任何一个子集合中(value可能有重复)
  6. Map中键值对的Key不能直接修改,value可以修改,如果要修改key,只能先将该key删除掉,然后再来进行重新插入。

Map底层结构
TreeMap
底层结构
红黑树
插入 / 删除 / 查找时间
复杂度
O(log N)
是否有序
关于 Key 有序
线程安全
不安全
插入 / 删除 / 查找区别
需要进行元素比较
比较与覆写
key 必须能够比较,否则会抛出
ClassCastException 异常
应用场景
需要 Key 有序场景下

🧿4. TreeMap的内部实现

TreeMap的内部实现是通过红黑树来存储键值对的。红黑树是一种自平衡的二叉查找树,它保证了在插入和删除操作后,树的高度保持相对较低,从而保证了高效的查找、插入和删除操作。 

🪬5.应用场景 

在实际应用中,如果你需要一个有序的映射表,并且不允许键重复,那么TreeMap是一个很好的选择。它既满足了有序性的需求,又提供了高效的操作性能。总而言之:

  • 当需要保持键的有序性且需要根据键快速查找值时,TreeMap是一个很好的选择。
  • 常用于需要按照特定顺序处理键值对的情况。

🗿四.总结与反思

人们在一起可以做出单独一个人所不能做出的事业;智慧+双手+力量结合在一起,几乎是万能的。——韦伯斯特

        在学习二叉搜索树和TreeSet/TreeMap的过程中,我深刻体会到了数据结构在编程中的应用和重要性。二叉搜索树作为一种特殊的二叉树,其特性包括每个节点的左子树都比当前节点小,右子树都比当前节点大,这使得在二叉搜索树中进行查找、插入和删除操作的时间复杂度可以达到O(log n),相比于线性搜索的O(n)有了显著的提升。而TreeSet和TreeMap的底层实现正是基于这种高效的数据结构——红黑树。

        红黑树是一种自平衡的二叉查找树,它通过红黑规则来保持树的平衡,确保任何节点的左子树的高度最多比右子树高1,从而保证了树的平衡性。在TreeSet和TreeMap中,插入、删除和查找操作的时间复杂度均为O(log n),这使得它们在处理大量数据时依然能够保持高效。

        学习二叉搜索树和TreeSet/TreeMap的过程中,我认识到数据结构的选择对于程序的性能有着至关重要的影响。虽然HashMap在查找、插入和删除操作上提供了O(1)的时间复杂度,但是它不保证元素的顺序,而TreeSet和TreeMap在保持有序的同时,牺牲了一部分时间复杂度。在实际应用中,我们需要根据具体需求选择合适的数据结构,以达到最优的性能。

        此外,在学习过程中,我也意识到了在多线程环境中使用TreeMap时需要注意同步问题。TreeMap不是线程安全的,如果需要在多线程环境中使用,需要程序员手动同步,或者通过包装等方式将TreeMap变成同步的。

        总的来说,学习二叉搜索树和TreeSet/TreeMap让我对数据结构和算法有了更深入的理解,也让我认识到在实际编程中选择合适的数据结构的重要性。在未来的学习和工作中,我会继续探索和运用这些知识,以提高程序的性能和可靠性。


🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀

以上,就是本期的全部内容啦,若有错误疏忽希望各位大佬及时指出💐

  制作不易,希望能对各位提供微小的帮助,可否留下你免费的赞呢🌸

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

3D应用开发工具HOOPS与云计算:推动工程设计行业的数字化转型

关于云计算 在信息技术迅猛发展的今天&#xff0c;云计算已经成为企业进行数字化转型的重要推手。云计算通过互联网提供包括服务器、存储、数据库、网络、软件、分析和智能等在内的计算服务&#xff0c;这些服务通常以按需供应的方式提供&#xff0c;允许用户根据使用量进行付…

ansible——INVENTORY主机清单

一、Inventory主机清单 Inventory支持对主机进行分组&#xff0c;每个组内可以定义多个主机&#xff0c;每个主机都可以定义在任何一个或多个主机组内 二、Inventory主机清单部署 2.1 前期准备 systemctl stop firewalld setenforce 0 yum install epel-release -y yum install…

vue+ant-design+formBuiler表单构建器——技能提升——form design——亲测有效

最近看到后端同事在弄一个后台管理系统&#xff0c;额&#xff0c;前端真的是夹缝中生存啊&#xff0c;AI抢饭碗&#xff0c;后端也想干前端的活儿。。。 他用到了表单构建器&#xff0c;具体效果如下: 网上有很多适用于ElementUi和ant-design的form design插件&#xff0c;下…

ISIS学习第一部分——isis基本概念

目录 一.ISIS与OSI模型 1.IS-IS&#xff0c;中间系统到中间系统 2.ES-IS,终端系统到中间系统 二.NET——ISIS中的“IP地址” &#xff08;1&#xff09;NET有3个部分: 1.Area ID 2.System ID 3.SEL &#xff08;2&#xff09;.前面是可变长的&#xff0c;如何进行区分…

##08 数据加载与预处理:PyTorch的心脏

文章目录 前言深入理解torch.utils.data数据集(Dataset)数据加载器(DataLoader) 实战演练&#xff1a;创建自定义数据集数据转换(Transform)数据加载总结 前言 在深度学习的宇宙中&#xff0c;数据是燃料&#xff0c;模型是发动机。而在PyTorch的世界中&#xff0c;torch.util…

【前端】前端数据本地化的多种实现方式及其优劣对比

前端数据本地化的多种实现方式及其优劣对比 在现代Web开发中&#xff0c;提高页面响应速度和改善用户体验是核心目标之一。数据本地化是其中一种实现方式&#xff0c;它通过在客户端存储数据来减少服务器请求&#xff0c;从而加快数据载入速度和改善用户的体验。本文将介绍前端…

Watchdog,一双专为 Python 而生的守护者之眼

大家好&#xff01;我是爱摸鱼的小鸿&#xff0c;关注我&#xff0c;收看每期的编程干货。 一个简单的库&#xff0c;也许能够开启我们的智慧之门&#xff0c; 一个普通的方法&#xff0c;也许能在危急时刻挽救我们于水深火热&#xff0c; 一个新颖的思维方式&#xff0c;也许能…

【数据库原理及应用】期末复习汇总高校期末真题试卷07

试卷 一、填空题&#xff08;每空1分&#xff0c;共10分&#xff09; 1.数据库管理系统在外模式、模式和内模式这三级模式之间提供了两层映象&#xff0c;其中 映象保证了数据的逻辑独立性。 2. 数据模型通常由 、数据操作和完整性约束三部分组…

Hive SQL-DML-insert插入数据

Hive SQL-DML-insert插入数据 1. 插入静态数据 可以直接插入具体的值到Hive表中&#xff1a; INSERT INTO TABLE tablename (column1, column2, column3) VALUES (value1, value2, value3),(value4, value5, value6),...;2. 插入查询结果 将一条查询的结果直接插入到另一个表中…

红帽发布Red Hat Enterprise Linux AI(RHEL AI)

红帽 2024 峰会正在科罗拉多州丹佛市举行…鉴于当前的时代背景&#xff0c;人工智能&#xff08;AI&#xff09;在此次峰会上占据了重要位置&#xff0c;因此红帽公司&#xff08;Red Hat&#xff09;也不甘人后宣布推出 RHEL AI。 红帽公司今天发布了 Red Hat Enterprise Lin…

汽车电子零部件(12):BEV, PHEV, HEV, FCEV

在考虑向电动汽车(纯电动汽车、HEV、FCEV、PHEV)过渡时,会听到很多缩写词。这可能有点让人不知所措,那就来谈谈它们的含义。 电动汽车EV (Electric Vehicles) 最广泛的类别是简单的电动汽车,即电动汽车。这些被定义为仅依靠电力进行推进的设计。这一群体包括流行的电动汽…

RTT事件集

事件集 事件集是线程间同步的机制之一&#xff0c;一个事件集可以包含多个事件&#xff0c;利用事件集可以完成一对多&#xff0c;多对多的线程间同步。 下面以坐公交为例说明事件&#xff0c;在公交站等公交时可能有以下几种情况&#xff1a; ①P1 坐公交去某地&#xff0c…

基于SpringBoot的高校推荐系统

项目介绍 当前&#xff0c;随着高等教育的不断普及&#xff0c;越来越多的学生选择考研究生来提高自身的学术水平和竞争力。然而&#xff0c;考研生在选择报考院校和专业时面临着众多的选择和信息不对称的问题。为了解决这些问题&#xff0c;一些网站和APP已经推出了相关的院校…

OpenAI泄密者加入马斯克xAI,技术版图扩张;OpenAI推出可识别DALL·E 3图像的AI检测工具

&#x1f989; AI新闻 &#x1f680; OpenAI泄密者加入马斯克xAI&#xff0c;技术版图扩张 摘要&#xff1a;最近&#xff0c;曾在OpenAI任职并被指控泄露机密的Pavel Izmailov迅速加入了马斯克旗下的xAI团队&#xff0c;成为研究员。在加入之前&#xff0c;Izmailov因涉嫌泄…

CAN报文总线仲裁机制

对于标准帧而言&#xff0c;有11位的标识符&#xff0c;也就是报文的ID。报文的ID值越小&#xff0c;优先级越高。如果有两个以上的ECU同时发送CAN报文&#xff0c;ID值小的报文可以发送成功。总线仲裁机制是一种非破坏性仲裁&#xff0c;是一种既不会造成已发送数据的延迟&…

天龙怀旧游戏python脚本

设置图&#xff1a; 游戏窗口最大化。​​​​​​​ 海贼洞这里定位你要回点的定位。 运行bat就行&#xff0c;脚本出错了还是会重新运行脚本&#xff0c;运行自动启动&#xff0c;end暂停脚本&#xff0c;home重新启动脚本 1. 我常用的是内挂回点脚本&#xff0c;下面都是…

Android内核之Binder通信写操作:binder_thread_write用法实例(七十一)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

vue3+elementPlus:el-input输入框设置数字小数点

<el-input-numberplaceholder"请输入"v-model.number"scope.row.threeValue"class"mx-4":step"0.001" //精度controls-position"right" //幅度/></template> 上一篇文章&#xff0c; vue3echarts&#xff1a;e…

如何更好地使用Kafka? - 事先预防篇

要确保Kafka在使用过程中的稳定性&#xff0c;需要从kafka在业务中的使用周期进行依次保障。主要可以分为&#xff1a;事先预防&#xff08;通过规范的使用、开发&#xff0c;预防问题产生&#xff09;、运行时监控&#xff08;保障集群稳定&#xff0c;出问题能及时发现&#…

windows10打印机共享完美解决方案

提到文件共享大家并不陌生,相关的还有打印机共享,这个多见于单位、复印部,在一个区域网里多台电脑共用一台打印机,打印资料非常方便,就包括在家里,我们现在一般都会有多台电脑或设备,通过家庭网络联接,如果共享一台打印机的话也是件便捷的事。 但是随着操作系统的更新…