Java Map和Set

Java Map和Set

文章目录

在这里插入图片描述

Map和Set

  1. map和set用于搜索
  2. 搜索树,二叉搜索树 -> AVL树 -> 红黑树
  3. AVL树:高度平衡的二叉搜索树
  4. TreeMap和TreeSet底层是红黑树,每次存储元素都得进行大小比较

二叉搜索树

  1. 二叉搜索树:如果左子树不为空,那么左子树所有节点都小于根节点,如果右子树不为空,那么右子树所有节点都大于根节点,它的左右子树都是二叉搜索树
  2. 二叉搜索树的中序遍历是有序的

查找

  1. 比key大往右找,比key小往左找
// 查找publicbooleansearch(int key){TreeNode cur = root;while(cur !=null){if(cur.val > key){ cur = cur.left;}elseif(cur.val < key){ cur = cur.right;}else{returntrue;}}returnfalse;}

分析:

  1. 时间复杂度:
    最好情况:O(logN),完全二叉树
    最坏情况:O(N),单分支的二叉树

插入

// 插入publicbooleaninsert(int key){TreeNode node =newTreeNode(key);TreeNode parent =null;if(root ==null){ root = node;returntrue;}TreeNode cur = root;while(cur !=null){if(cur.val < key){ parent = cur; cur = cur.right;}elseif(cur.val > key){ parent = cur; cur = cur.left;}else{// 在二叉搜索树中只能不能有相同的数字,比如5,有一个5就可以了,只要有这个数就可以了returnfalse;}}if(parent.val < key){ parent.right= node;}else{ parent.left = node;}returntrue;}

删除

  1. 第一种情况:cur.left == null
    要删除的节点是cur
    cur是根节点
    cur是某个节点的左边
    cur是某个节点的右边
在这里插入图片描述


2. 第二种情况:cur.right == null
要删除的节点是cur
cur是根节点
cur是某个节点的左边
cur是某个节点的右边

在这里插入图片描述


3. 第三种情况:cur.left != null && cur.right != null
使用替换法进行删除

替换为左树中最大的值
或者是右树中最小的值
替换完之后删除这个去替换的值

在这里插入图片描述


在这里插入图片描述
// 删除privatevoidremoveNode(TreeNode cur,TreeNode parent){if(cur.left ==null){// 要删除的是根节点if(cur == root){ root = cur.right;}elseif(cur == parent.left){ parent.left = cur.right;}else{ parent.right = cur.right;}}elseif(cur.right ==null){if(cur == root){ root = cur.left;}elseif(cur == parent.left){ parent.left = cur.left;}else{ parent.right = cur.left;}}else{// cur.left != null && cur.right != nullTreeNode parentTarget = cur;TreeNode target = cur.right;// 在右树中找最小值while(target.left !=null){ parentTarget = target; target = target.left;}// 直到找到右树中的最左边的树 cur.val = target.val;// 删除targetif(parentTarget.left == target){ parentTarget.left = target.right;}else{// parentTarget.right == target parentTarget.right = target.right;}}}

Map

  1. map是一种(k,v)结构的数据结构
  2. map可以进行去重,TreeMap不可以插入null的key,HashMap可以插入null的key,因为红黑树是要进行比较的,哈希表是不进行比较的
Map<String,Integer> map =newTreeMap<>();// 底层是红黑树,查找的时间复杂度O(N*logN)Map<String,Integer> map1 =newHashMap<>();// 底层是哈希表,查找的时间复杂度O(1)// 哈希表 = 数组 + 链表 + 红黑树

Map的使用

在这里插入图片描述
publicstaticvoidmain(String[] args){Map<String,Integer> map =newTreeMap<>();// 底层是红黑树,查找的时间复杂度O(N*logN)// 插入元素 map.put("push",3);// push出现了3次// 获取元素,给定一个key值可以获取它的value值Integer val = map.get("push");Integer val1 = map.get("aaa");// null// 获取val值,如果没有这个值,返回一个默认值Integer val2 = map.getOrDefault("bbb",99999);System.out.println(val);// 删除key值// map.remove("push");// 把所有的key放入一个集合中Set<String> set = map.keySet();System.out.println(set);// 获取values中的所有值ArrayList<Integer> value =newArrayList(map.values());System.out.println(value);// 把Map.Entry<String,Integer>当做Set中的一个节点// map.entrySet()用于获取这种节点Set<Map.Entry<String,Integer>> entrySet = map.entrySet();for(Map.Entry<String,Integer> entry : entrySet){System.out.println("key: "+ entry.getKey()+" value: "+ entry.getValue());}// boolean map.containsKey("push"); 判断是否含有key// boolean map.containsValue(3); 判断是否含有valueMap<String,Integer> map1 =newHashMap<>();// 底层是哈希表,查找的时间复杂度O(1)// 哈希表 = 数组 + 链表 + 红黑树}

Set

  1. set是一种只有key的模型

Set的使用

  1. Set是要进行去重的
  2. TreeSet不可以插入null的key,HashSet可以插入null的key,因为红黑树是要进行比较的,哈希表是不进行比较的
publicstaticvoidmain(String[] args){Set<String> set =newTreeSet<>(); set.add("push"); set.add("hello"); set.add("world");// set是无序的System.out.println(set);Iterator<String> it = set.iterator();while(it.hasNext()){System.out.println(it.next());}}

哈希表

  1. 查找可以一次定位到该元素,时间复杂度为O(1)

哈希冲突(碰撞):不同的key通过相同的哈希函数得到相同的值
哈希冲突是必然产生的,我们要做的是降低冲突的概率

在这里插入图片描述


解决哈希冲突:哈希函数的设计要合理
哈希函数要简单
哈希表中要均匀分到数组中去
哈希表的范围要合理,比如有m个地址,存储位置就是[0,m-1]

在这里插入图片描述

负载因子的调节(重点)

  1. 负载因子影响了哈希冲突,负载因子越大冲突率越高
  2. 哈希表中的负载因子定义为:
    a = 填入表中的元素个数 / 哈希表的长度
    比如:a = 8 / 10 = 0.8

如果降低冲突率就要降低负载因子,因此要扩容哈希表的大小,不增加插入的元素是不现实的,给定一个阈值,如果超过了就扩大哈希表的容量

在这里插入图片描述

闭散列

  1. 开放定址法,如果没有达到阈值,但是冲突了,就放到冲突的下一个空的位置上,这个也叫线性探测
  2. 线性探测的缺点:把冲突的元素都集中放到了一起
  3. 二次探测:为了解决线性探测的缺点,通过公式进行处理,H0是当前冲突的位置,i是出现冲突的次数,m是哈希表的大小,Hi表示冲突后,下一次要放的位置
在这里插入图片描述


4. 线性探测对于空间的利用率不高

开散列

  1. 开散列:又叫链地址法,为了解决空间利用率不高的问题,开散列是数组 + 链表 + 红黑树的模式
  2. 把冲突的元素挂到同一个空间下的链表上
  3. Java是采用开散列的方式实现的
在这里插入图片描述


4. 扩容之后需要重新哈希,因为数组长度变了,要重新计算节点存放的位置
5. 遍历哈希数组中每个数组元素,都要重新计算节点位置

在这里插入图片描述
packageDemo1;importjava.util.Arrays;publicclassHashBuck{// 链表数组,数组中的每一个元素都时链表的头结点publicclassNode{publicint key;publicint val;publicNode next;publicNode(int key,int val){this.key = key;this.val = val;}}publicNode[] array;publicint usedSize;publicstaticfinalfloat DEFAULT_LOAD_FACTOR =0.75f;publicHashBuck(){ array =newNode[10];}publicvoidput(int key,int value){int index = key % array.length;// 遍历index下标的链表 是否存在key 存在就更新value 不存在就头插这个节点Node node =newNode(key,value);// 该链表的头结点Node cur = array[index];while(cur !=null){if(cur.key == key){// 如果插入的这个key相同就替换这个key cur.val = value;return;} cur = cur.next;}// 没有找到这个节点就头插 node.next = array[index]; array[index]= node; usedSize++;// 负载因子大于阈值if(doLoadFactor()> DEFAULT_LOAD_FACTOR){// 扩容// array = Arrays.copyOf(array,2*array.length);resize();}}privatevoidresize(){// 建一个新的数组Node[] newArray =newNode[2*array.length];for(int i =0;i < array.length;i++){Node cur = array[i];while(cur !=null){Node tmp = cur.next;// 每次都要算新数组的下标因为是一个链表有很多个节点int newIndex = cur.key % newArray.length;// 头插法 cur.next = newArray[newIndex]; newArray[newIndex]= cur; cur = tmp;}} array = newArray;}// 计算负载因子privatefloatdoLoadFactor(){return usedSize *1.0f/ array.length;}// 获取对应key的value值publicintget(int key){int index = key % array.length;Node cur = array[index];while(cur !=null){if(cur.key == key){// 如果插入的这个key相同就替换这个keyreturn cur.val;} cur = cur.next;}return-1;}}
  1. HashMap是线程不安全的,因为采用了头插法,后面采用了尾插法变得安全了,ConcurrentHashMap是线程安全的,之后学到了线程就可以理解了
  2. 如果key是String,Person类型就不能除以数组的长度了,该怎么找到对应的下标呢?
    可以用hashcode来将自定义类型转化为整形类型

hashCode和equals

在这里插入图片描述

HashMap和HashSet

publicstaticvoidmain(String[] args){HashMap<String,Integer> hashMap =newHashMap<>(); hashMap.put("hello",2); hashMap.put("abcde",10); hashMap.put("abc",11);Integer val = hashMap.get("hello");System.out.println(val);// 遍历mapSystem.out.println(hashMap);for(Map.Entry<String,Integer> entry : hashMap.entrySet()){System.out.println("key:"+ entry.getKey()+" value:"+ entry.getValue());}// Map不支持迭代器遍历,Set支持迭代器遍历// 可以将Map转化为Set进行迭代器遍历HashMap<Student,Integer> hashMap1 =newHashMap<>(); hashMap1.put(newStudent(),2); hashMap1.put(newStudent(),2); hashMap1.put(null,2);// TreeMap<Student,Integer> hashMap2 = new TreeMap<>();// hashMap2.put(new Student(),3);// hashMap2.put(new Student(),3);// Sutdent不能进行比较// set可以去重,Set的底层是HashMap// 每次存储元素的时候,默认的value都是一个Object对象HashSet<String> set =newHashSet<>(); set.add("hello"); set.add("world"); set.add("hello");System.out.println(set);}

面试题

只出现一次的数字
宝石与石头
旧键盘
随机链表的复制

在这里插入图片描述

统计6个数中数字出现的次数

publicstaticvoidmain(String[] args){int[] array ={1,1,2,2,3,3};HashMap<Integer,Integer> map =newHashMap<>();for(int i =0;i < array.length;i++){if(!map.containsKey(array[i])){ map.put(array[i],1);}else{int k = map.get(array[i]); k++; map.put(array[i],k);}}System.out.println(map);}

前k个高频单词

在这里插入图片描述


如果频率相同放入堆中要使用大根堆,要让love排在i的前面

在这里插入图片描述
classSolution{publicList<String>topKFrequent(String[] words,int k){// 1. 统计单词出现的次数Map<String,Integer> map =newHashMap<>();for(String s : words){if(!map.containsKey(s)){ map.put(s,1);}else{int val = map.get(s); map.put(s,val+1);}}// 2. 把单词和出现的次数当做一个整体放入小根堆中PriorityQueue<Map.Entry<String,Integer>> minHeap =newPriorityQueue<>(newComparator<Map.Entry<String,Integer>>(){publicintcompare(Map.Entry<String,Integer> o1,Map.Entry<String,Integer> o2){// 放元素的时候,如果频率相同,我们转变为大根堆 -> 按照单词的字典序进行排序if(o1.getValue().compareTo(o2.getValue())==0){return o2.getKey().compareTo(o1.getKey());}return o1.getValue().compareTo(o2.getValue());}});for(Map.Entry<String,Integer> entry : map.entrySet()){if(minHeap.size()< k){// 没有放满小根堆 minHeap.add(entry);}else{// 放满了和堆顶元素比较大小// 如果比堆顶元素还大,就入堆int v = minHeap.peek().getValue();if(v < entry.getValue()){ minHeap.poll(); minHeap.offer(entry);}else{// 出现频率相同,比较字典序大小if(v == entry.getValue()){if(minHeap.peek().getKey().compareTo(entry.getKey())>0){ minHeap.poll(); minHeap.offer(entry);}}}}}// 2 3 4 -> 4 3 2List<String> arr =newArrayList<>();for(int i =0;i < k;i++){Map.Entry<String,Integer> top = minHeap.poll(); arr.add(top.getKey());}// 逆置Collections.reverse(arr);return arr;}}

HashMap的源码

如果达到一定条件会把哈希表编程红黑树:如果链表的长度大于8并且数组的长度大于64就会进行树化

在这里插入图片描述

Read more

盘点IDEA中那些实用的GIT小技巧

盘点IDEA中那些实用的GIT小技巧

作者:唐叔在学习 专栏:唐叔的Java实践 关键词:IDEA技巧,开发效率优化, 代码比较, 团队协作, 程序员必备, 代码管理 一句话:还在用Commit和Pull?唐叔教你解锁IDEA中那些隐藏的Git神操作,让代码管理变得如此简单! 文章目录 * 前言 * 🔄 一、智能更新项目:Update Project * 🔍 二、精准代码比较:Git Show Diff * 1. 当前修改比较:Git Show Diff * 2. 分支/标签比较:Compare Branch or Tag * 📜 三、追溯代码历史:Show History for Selection * 💾 四、灵活提取修改:Patch * 📦 五、暂存未提交代码:Uncommitted

By Ne0inhk
最新版 Kimi K2.5 进阶实战全攻略:从开源部署到 Agent 集群搭建(视频理解 + 多模态开发 + 高并发调优)

最新版 Kimi K2.5 进阶实战全攻略:从开源部署到 Agent 集群搭建(视频理解 + 多模态开发 + 高并发调优)

1 技术背景与核心架构原理 1.1 技术定位与版本说明 Kimi K2.5 是月之暗面于2026年初发布的开源多模态大语言模型,聚焦长上下文理解、原生多模态交互、Agent 原生支持三大核心能力,针对工业级落地场景完成了全链路优化。本次实战覆盖的开源版本包括: * kimi-k2.5-chat-70b:基础对话版,支持2000K token 上下文窗口,原生适配工具调用 * kimi-k2.5-multimodal-70b:多模态完整版,新增图像、长视频时序理解能力,支持最长10小时连续视频输入 * kimi-k2.5-agent-70b:Agent 优化版,强化多轮工具链执行、分布式状态同步能力,适配集群化部署 * 量化衍生版本:AWQ 4bit/8bit、FP8 量化版,适配低显存硬件环境,精度损失控制在1%以内 1.2 核心架构与技术亮点 1.2.1

By Ne0inhk
最强开源多模态大模型它来啦——一文详解Qwen3.5核心特性

最强开源多模态大模型它来啦——一文详解Qwen3.5核心特性

前言 各位小伙伴新年好!新的一年祝大家龙马精神、阖家幸福、身体健康、事业进步!2025 年 DeepSeek 发布的 DeepSeek-R1 模型震惊全球,此后国内各大厂商充分发挥“能征善战”的拼劲,纷纷选择重大节日推出新品。今年除夕夜,阿里 Qwen 团队再次放出大招——Qwen3.5 模型正式开源,为国产大模型阵营再添一员猛将。 Qwen3.5 是目前全球最强的原生多模态开源大模型,不仅支持图片和视频的多模态输入,在对话、推理、编程、Agent 构建等方面也样样精通。其综合能力已达到 GPT-5.2、Gemini 3.0 Pro 的平均水平,推理能力尤为突出。例如那道曾让无数模型“翻车”的逻辑题——“50 米距离该走路还是开车去洗车”,Qwen3.5 也能轻松作答。

By Ne0inhk
Neo4j下载安装教程手把手演示(Windows、MacOS、Linux等平台安装包&官方文档、查询语言文档&均附下载链接)

Neo4j下载安装教程手把手演示(Windows、MacOS、Linux等平台安装包&官方文档、查询语言文档&均附下载链接)

目录 * Neo4j 简介 * Neo4j 下载 * Neo4j 安装(演示为Windows10环境) * 配置环境变量 * 启动和访问 * 参考文档下载 Neo4j 简介 最近正好做项目需要用到知识图谱,记录一下。 Neo4j 是一个高性能、基于图形数据库的 NoSQL 数据库,支持复杂的关系建模和查询,使用 Cypher 语言进行查询操作。它广泛应用于社交网络、推荐系统、知识图谱等领域。 官方网站: https://neo4j.com Neo4j 下载 方式①: * Windows * Linux/MacOS * Red Hat Linux * Debian/Ubuntu 访问官网:Neo4j 下载页面 方式②:离线下载安装包,点击即下(推荐!!!): Neo4j

By Ne0inhk