在这里插入图片描述
在这里插入图片描述
⬅(click)


大家好!我是你们的老朋友——想不明白的过度思考者!今天我们要一起探索Java中两个神奇的数据结构:Map和Set!准备好了吗?让我们开始这场魔法之旅吧!🎩

🎯 先来点开胃菜:二叉搜索树(BST)

🌳 什么是二叉搜索树?

想象一下,你有一棵神奇的树,左边的果子都比树根小,右边的果子都比树根大!这就是我们的二叉搜索树!

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树
package Tree;//表示树的节点
class Node {public int key;public Node left;public Node right;public Node(int key) {this.key = key;}@Overridepublic String toString() {return "Node{" +"key=" + key +", left=" + left +", right=" + right +'}';}
}public class BinarySearchTree {private Node root = null;//把新的元素插入到树中public void insert(int key) {//如果当前是空树,那就直接用root指向新节点即可Node newNode = new Node(key);if (root == null) {root = newNode;}// 如果是普通的树,需要找到哦插入位置,再去进行插入//cur用来找待插入元素的位置//parent记录cur的父元素Node cur = root;Node parent = null;while (cur != null) {if(key<cur.key) {//往左找parent = cur;cur = cur.left;}else if(key>cur.key) {//往右找parent = cur;cur = cur.right;}else {//对于相等的情况,存在不同的解决方式//当前不允许重复key存在,并且是Set只保存key,直接returnreturn;}}//通过上述循环最终得到的结果就是cur为空//此时的parent就是叶子节点,也就是新插入元素的父亲,此时就是要把newNode插入到parent的子节点上//新节点,应该在parent的左子树还是右子树呢??直接比较大小if (key> parent.key){parent.right = newNode;}else {parent.left = newNode;}}public void remove(int key) {if (root == null) {return;}//查找要删除节点的位置,记录其父节点Node cur = root;Node parent = null;while (cur != null) {if(key<cur.key) {parent = cur;cur = cur.left;}else if(key>cur.key) {parent = cur;cur = cur.right;}else {//找到了removeNode(parent, cur);return;}}}private void removeNode(Node parent, Node cur) {//具体删除节点要考虑四种情况//1.没有子树if(cur.right == null && cur.left == null) {//1.1如果cur就是root,需要对root进行调整if(cur == root) {//说明整棵树只有root一个节点,直接把root设置为空root = null;}//1.2如果cur不是root,同时cur是parent的左子树if (cur == parent.left) {parent.left = null;return;}//1.3如果cur不是root,同时cur是parent的右子树if (cur == parent.right) {parent.right = null;return;}//稳妥起见加个returnreturn;}//2.只有左子树if(cur.left != null && cur.right == null) {//2.1cur为rootif(cur == root){root = cur.left;return;}//2.2cur不为root,且cur是parent的左子树if (cur == parent.left) {parent.left = cur.left;return;}//2.3cur不为root,且cur是parent的右子树if (cur == parent.right) {parent.right = cur.left;return;}}//3.只有右子树if(cur.left == null && cur.right != null) {//3.1只有rootif(cur == root){root = cur.right;return;}//3.2cur不是root,且cur是parent的左子树if (cur == parent.left) {parent.left = cur.right;return;}//3.3cur不是root,且cur是parent的右子树if (cur == parent.right) {parent.right = cur.right;return;}}//4.左右都有子树if(cur.left != null && cur.right != null) {// 这种情况下,不需要考虑 cur 是不是 root的情况,并没有真正的删除 cur指向的节点,即使 cur 是 root,也无需修改 root 的指向//因为实际删除的是“替罪羊节点”//4.1首先需要找到右子树中的最小值 =>替罪羊,//后续要删除替罪羊,也顺便把替罪羊的父亲,记录一下.Node goat = cur.right;Node goatParent= cur;while (goat.left != null) {goatParent = goat;goat = goat.left;}//循环结束后。goat指向的就是cur右子树的最左侧元素//4.2移花接木,把替罪羊节点的值复制到cur节点中cur.key = goat.key;//4.3真正删除goat节点,因为goat是没有左子树的,让goatParent直接连上goat的右子树即可// 即使goat的右子树也是空也不影响if(goat == goatParent.left){goatParent.left = goat.right;}else {goatParent.right = goat.right;}}}//查找key是否在树中,如果存在则返回对应节点位置,如果不存在则返回nullprivate Node find(int key) {if (root == null) {return null;}Node cur = root;while (cur != null) {if(key<cur.key) {cur = cur.left;}else if(key>cur.key) {cur = cur.right;}else {//相等,找到了return cur;}}return null;}//先序遍历private static void preOrder(Node root) {if (root == null) {return;}System.out.print(root.key + " ");preOrder(root.left);preOrder(root.right);}//中序遍历private static void inOrder(Node root) {if (root == null) {return;}inOrder(root.left);System.out.print(root.key + " ");inOrder(root.right);}public void print(){//先打印先序遍历System.out.println("先序遍历结果:");preOrder(root);System.out.println();//在打印中序遍历System.out.println("中序遍历结果:");inOrder(root);//有了先序和中序就能够画出树的结构}public static void main(String[] args) {int[] arr = {1, 3, 2, 6, 5, 7, 8, 9, 10, 0};//BinarySearchTree也总被缩写成BSTBinarySearchTree tree = new BinarySearchTree();//循环插入for(int key: arr){tree.insert(key);}tree.print();System.out.println();System.out.println(tree.find(7));}
}

🎭 BST的表演时刻

操作最佳情况(完全二叉树)最差情况(单支树)
查找O(logN)O(N)
插入O(logN)O(N)
删除O(logN)O(N)

💡 小贴士:Java中的TreeMap和TreeSet就是用红黑树(BST的升级版)实现的哦!

🎩 主角登场:Map和Set

🗺️ Map:你的万能字典

Map就像你的通讯录,名字(Key)对应电话(Value),而且名字不能重复!

Map<String, String> heroNicknames = new HashMap<>();
heroNicknames.put("林冲", "豹子头");
heroNicknames.put("李逵", "黑旋风");
heroNicknames.put("宋江", "及时雨");// 获取外号
System.out.println(heroNicknames.get("林冲"));  // 输出:豹子头// 遍历所有英雄
for (Map.Entry<String, String> entry : heroNicknames.entrySet()) {System.out.println(entry.getKey() + "的外号是:" + entry.getValue());
}
  • Tip:使用put方法时:
    若key不同,value相同则新增键值对
    若key相同,value不同则为修改对应的value

🎭 Map的两种实现对比

特性TreeMap(红黑树)HashMap(哈希表)
底层结构红黑树哈希桶
时间复杂度O(logN)O(1)
是否有序Key有序无序
允许nullKey不能为nullKey和Value都可以为null

🎪 Set:独一无二的马戏团

Set就像一个不允许重复演员的马戏团,每个演员都是独一无二的!

Set<String> fruitSet = new HashSet<>();
fruitSet.add("苹果");
fruitSet.add("香蕉");
fruitSet.add("橙子");
fruitSet.add("苹果");  // 这个不会被添加进去System.out.println(fruitSet.contains("香蕉"));  // 输出:true
System.out.println(fruitSet.size());          // 输出:3

🎭 Set的两种实现对比

特性TreeSet(红黑树)HashSet(哈希表)
底层结构红黑树哈希桶
时间复杂度O(logN)O(1)
是否有序Key有序无序
允许null不允许允许

🔮 哈希表:数据结构的魔法帽

🎩 哈希函数:魔法咒语

哈希函数就像把名字变成数字的咒语:

int hashCode = "魔法".hashCode();  // 返回一个魔法数字

⚡ 哈希冲突:当两个咒语撞车了

当不同的Key计算出相同的哈希值,就发生了冲突!我们有几种解决办法:

  1. 开放地址法(线性探测/二次探测)

    • 线性探测:h(key) = (h(key) + i) % size
    • 二次探测:h(key) = (h(key) + i²) % size
  2. 链地址法(哈希桶)

    • 每个位置放一个链表,冲突的元素都挂在链表上

🌟 哈希桶实现:我们的魔法实验室

public class HashBucket {static class Node {int key, value;Node next;public Node(int key, int value) {this.key = key;this.value = value;}}private Node[] array;private int size;private static final double LOAD_FACTOR = 0.75;public HashBucket() {array = new Node[8];size = 0;}public int put(int key, int value) {int index = key % array.length;// 查找key是否已存在for (Node cur = array[index]; cur != null; cur = cur.next) {if (key == cur.key) {int oldValue = cur.value;cur.value = value;return oldValue;}}// 插入新节点Node node = new Node(key, value);node.next = array[index];array[index] = node;size++;// 检查是否需要扩容if ((double)size / array.length >= LOAD_FACTOR) {resize();}return -1;}private void resize() {Node[] newArray = new Node[array.length * 2];for (int i = 0; i < array.length; i++) {Node next;for (Node cur = array[i]; cur != null; cur = next) {next = cur.next;int index = cur.key % newArray.length;cur.next = newArray[index];newArray[index] = cur;}}array = newArray;}public int get(int key) {int index = key % array.length;for (Node cur = array[index]; cur != null; cur = cur.next) {if (key == cur.key) return cur.value;}return -1;}
}

📊 哈希表性能分析

因素影响
哈希函数设计决定冲突率高低
负载因子通常控制在0.75以下
冲突解决方法影响查找效率和内存使用
扩容机制影响性能和内存使用的平衡

🎯 实战演练:OJ题目解析

1. 只出现一次的数字

题目:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

魔法解法:使用异或运算的特性!

public int singleNumber(int[] nums) {int result = 0;for (int num : nums) {result ^= num;}return result;
}

2. 宝石与石头

题目:给定字符串J代表宝石的类型,S代表你拥有的石头。你想知道你拥有的石头中有多少是宝石。

魔法解法:使用HashSet!

public int numJewelsInStones(String J, String S) {Set<Character> jewels = new HashSet<>();for (char c : J.toCharArray()) {jewels.add(c);}int count = 0;for (char c : S.toCharArray()) {if (jewels.contains(c)) count++;}return count;
}

🎓 知识总结:思维导图

在这里插入图片描述

🎉 结语:选择你的魔法武器

今天我们一起探索了Map和Set的魔法世界,从二叉搜索树到哈希表,从TreeMap到HashMap,每个数据结构都有它独特的魔法特性!

记住:

  • 需要快速查找?选HashMap/HashSet!
  • 需要有序存储?选TreeMap/TreeSet!
  • 遇到哈希冲突?试试链地址法!

希望这篇博客能像魔法一样帮助你理解这些数据结构!

请添加图片描述

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

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

相关文章

Unreal Engine UStaticMeshComponent

UnrealUnreal Engine - UStaticMeshComponent&#x1f3db; 定义&#x1f3db; 类继承⚡ 关键特性⚙️ 常见配置&#x1f6e0;️ 使用方法&#x1f4da; 在 C 中使用&#x1f4da; 在蓝图中使用&#x1f3ae; 典型应用场景&#x1f4da; 常见子类与用途&#x1f4dd; 小结Unrea…

demo 汽车之家(渲染-筛选-排序-模块抽离数据)

效果图展示&#xff1a;代码截图注释详情实现笔记总体目标&#xff08;按需求点对照代码&#xff09;数据模块化、整体渲染框架、筛选/排序的高亮与行为&#xff0c;全部已在 Index.ets CarData.ets 落地。下面按图片需求 2~4 点逐条总结&#xff0c;并给出关键代码定位与“为…

双重机器学习DML介绍

本文参考&#xff1a; [1]文心一言回答&#xff1b; 一、核心原理与数学框架 双重机器学习&#xff08;Double Machine Learning, DML&#xff09;由Chernozhukov等学者于2018年提出&#xff0c;是一种结合机器学习与传统计量经济学的因果推断框架。其核心目标是在高维数据和非…

【图像算法 - 21】慧眼识虫:基于深度学习与OpenCV的农田害虫智能识别系统

摘要&#xff1a; 在现代农业生产中&#xff0c;病虫害是影响作物产量和品质的关键因素之一。传统的害虫识别依赖人工巡查&#xff0c;效率低、成本高且易出错。本文将介绍如何利用深度学习与OpenCV构建一套高效的农田害虫智能识别系统。该系统能够自动识别10类常见农业害虫&a…

循环神经网络实战:GRU 对比 LSTM 的中文情感分析(三)

循环神经网络实战&#xff1a;GRU 对比 LSTM 的中文情感分析&#xff08;三&#xff09; 文章目录循环神经网络实战&#xff1a;GRU 对比 LSTM 的中文情感分析&#xff08;三&#xff09;前言数据准备&#xff08;与 LSTM 相同&#xff09;模型搭建&#xff08;GRU&#xff09;…

学习游戏制作记录(制作提示框以及使用键盘切换UI)8.21

1.制作装备提示框创建提示框&#xff0c;添加文本子对象&#xff0c;用来描述名称&#xff0c;类型以及属性加成挂载垂直分配组件和文本大小适配组件&#xff0c;这样图像会根据文本大小来调整自己创建UI_ItemTip脚本并挂载在文本框上&#xff1a;[SerializeField] private Tex…

chapter07_初始化和销毁方法

一、简介 一个Bean&#xff0c;在进行实例化之后&#xff0c;需要进行两种初始化 初始化属性&#xff0c;由PropertyValues进行赋值初始化方法&#xff0c;由ApplicationContext统一调用&#xff0c;例如加载配置文件 Bean的初始化与销毁&#xff0c;共有三种方式&#xff08;注…

open webui源码分析6-Function

一、Functions简介 可以把Tools作为依赖于外部服务的插件&#xff0c;Functions就是内部插件&#xff0c;二者都是用来增强open webui的能力的。Functions是轻量的&#xff0c;高度可定制的&#xff0c;并且是用纯Python编写的&#xff0c;所以你可以自由地创建任何东西——从新…

C2039 “unref“:不是“osgEarth::Symbology::Style”的成员 问题分析及解决方法

在osgEarth2.10中实现多线段连续测量功能时,遇到下图中的错误; 经过测试和验证,主要问题出现在下图圈出代码的定义上 图22-1 对于22-1中的两个变量这样定义是错误的。因为Style类没有继承自osg::Referenced,因此不能与osg::ref_ptr配合使用

GitHub 热榜项目 - 日榜(2025-08-19)

GitHub 热榜项目 - 日榜(2025-08-19) 生成于&#xff1a;2025-08-19 统计摘要 共发现热门项目&#xff1a;12 个 榜单类型&#xff1a;日榜 本期热点趋势总结 本期GitHub热榜呈现三大技术热点&#xff1a;1&#xff09;AI原生开发持续爆发&#xff0c;Archon OS、Parlant等…

ingress 配置ssl证书

模拟环境举例&#xff1a; # 生成带 OU 的证书配置文件 cat > csr.conf <<EOF [ req ] default_bits 2048 prompt no default_md sha256 distinguished_name dn[ dn ] C CN ST Beijing L Beijing O YourCompany, Inc. # 组织名称 (必填) OU DevOps De…

Pandas 合并数据集:concat 和 append

文章目录Pandas 合并数据集&#xff1a;concat 和 append回顾&#xff1a;NumPy 数组的拼接使用 pd.concat 进行简单拼接重复索引将重复索引视为错误忽略索引添加多级索引&#xff08;MultiIndex&#xff09;键使用连接&#xff08;Join&#xff09;方式拼接append 方法Pandas …

2025年5月架构设计师综合知识真题回顾,附参考答案、解析及所涉知识点(七)

本文主要回顾2025年上半年(2025-5-24)系统架构设计师考试上午综合知识科目的选择题,同时附带参考答案、解析和所涉知识点。 2025年5月架构设计师综合知识真题回顾,附参考答案、解析及所涉知识点(一) 2025年5月架构设计师综合知识真题回顾,附参考答案、解析及所涉知识点(…

面向RF设计人员的微带贴片天线计算器

微带贴片天线和阵列可能是仅次于单极天线和偶极天线的最简单的天线设计。这些天线也很容易集成到PCB中&#xff0c;因此通常用于5G天线阵列和雷达等高级系统。这些天线阵列在基谐模式和高阶模式下也遵循一组简单的设计方程&#xff0c;因此您甚至可以在不使用仿真工具的情况下设…

明基RD280U编程显示器深度测评:码农的「第二块键盘」竟然会发光?

文章目录前言一、开箱篇&#xff1a;当理工男遇到「俄罗斯套娃式包装」二、外观篇&#xff1a;深空灰的「代码容器」1. 桌面变形记2. 保护肩颈的人体工学设计三、显示篇&#xff1a;给代码做「光子嫩肤」1. 28寸超大大屏 3:2屏比 4K超清2.专业编程模式&#xff0c;让代码一目…

算法114. 二叉树展开为链表

题目&#xff1a;给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。 展开后的单链表应该与二叉树 先序遍历 顺序相同。…

智慧能源管理系统:点亮山东零碳园区的绿色引擎

一、概述在全球积极践行“双碳”目标的时代浪潮下&#xff0c;山东作为经济大省&#xff0c;正全力推动产业的绿色变革&#xff0c;零碳园区建设成为其中的关键一环。《山东省零碳园区建设方案》明确规划&#xff0c;到2027年建成15个左右省级零碳园区 &#xff0c;到2030年进一…

分布式日志分析平台(ELFK 与 EFK)理论

一、日志分析平台核心概念在分布式系统中&#xff0c;日志是系统运行状态监控、问题排查和业务分析的重要依据。随着系统规模扩大&#xff0c;单机日志管理方式已无法满足需求&#xff0c;分布式日志分析平台应运而生。其核心目标是实现日志的集中收集、统一处理、高效存储和可…

CoreShop微信小程序商城框架开启多租户-添加一个WPF客户端以便进行本地操作--读取店铺信息(6)

本节内容&#xff0c;使用登录的token进行店铺信息读取&#xff0c;顺利的话&#xff0c;进行EXCEL上传测试。 1。在后台编写 读取店铺信息代码 1.1 查看原来铺店信息在什么位置&#xff0c;店铺的表格为CoreCmsStore#region 获取列表// POST: Api/CoreCmsStore/GetPageList///…

UE5关卡蓝图能不能保存副本呀?

提问 关卡蓝图能不能保存副本呀&#xff1f; 回答 在 UE 里&#xff0c;“关卡蓝图&#xff08;Level Blueprint&#xff09;”本身其实是不能直接复制/保存成独立资源的&#xff0c;因为它和具体的 **Level&#xff08;.umap 文件&#xff09;**是绑定的——相当于一个“场景脚…