当前位置: 首页 > news >正文

Java Map和Set

目录

    • 1. 二叉排序树(二叉搜索树)
      • 1.1 二叉搜索树的查找
      • 1.2 二叉搜索树的插入
      • 1.3 二叉搜索树的删除(7种情况)
      • 1.4 二叉搜索树和TreeMap、TreeSet的关系
    • 2. Map和Set的区别与联系
      • 2.1 从接口框架的角度分析
      • 2.2 从存储的模型角度分析【2种模型】
    • 3. 关于Map
      • 3.1 Map的注意事项
      • 3.2 TreeMap 和 HashMap的对比
      • 3.3 Map.Entry<k,v>的用法 (遍历)
    • 4. 关于Set
      • 4.1 Set的注意事项
      • 4.2 TreeSet 和 HashSet的对比
      • 4.3 迭代器遍历Set
    • 5. 哈希表
      • 5.1 哈希函数
      • 5.2 冲突
      • 5.3 冲突的解决:开放地址法和链地址法
      • 5.4 哈希表与Java集合类的关系
    • 6. HashMap源码分析
      • 6.1 成员变量
      • 6.2 构造方法
      • 6.3 put方法源码

1. 二叉排序树(二叉搜索树)

二叉搜索树又称二叉排序树

  • 若左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 左右子树也分别是二叉搜索树
    【左小右大】

1.1 二叉搜索树的查找

【二叉搜索树的查找,一般情况下一次可以干掉很多数据】
为了保证每次可以干掉很多数据
思路:取遍历节点为cur,每次要查找的值val和cur的val进行比较,如果要查找的值比cur的val小,则去cur的左边继续查找,如果大则去cur的右边继续查找。

    public boolean search(int val) {TreeNode cur = root;while (cur != null) {if (cur.val == val) {return true;}else if (cur.val > val) {cur = cur.left;}else {cur = cur.right;}}return false;}

1.2 二叉搜索树的插入

思路:整体思路与查找的思路类似,但是二叉搜索树的每次插入的节点一定是叶子节点,因此需要记录待插入节点的双亲。
当cur为空时,parent记录了待插入结点的父亲位置,再用val和parent的val比较进行插入。

    public void insert (int val) {Node node = new Node(val);if (root == null) {root = node;return;}Node cur = root;Node parent = root;while (cur != null) {if (cur.val == val) {return;}else if (cur.val > val) {parent = cur;cur = cur.left;}else {parent = cur;cur = cur.right;}}if (parent.val > val) {parent.left = node;}else {parent.right = node;}}

1.3 二叉搜索树的删除(7种情况)

设待删除结点为cur,待删除结点的双亲结点为parent
整体看分以下3种大情况:
①cur的左为空
②cur的右为空
③cur的左和右都不为空
继续细分:cur是不是root;cur不是root的话,是parent的左还是parent的右
故有3 + 3 + 1 = 7种情况。

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

    1.4 二叉搜索树和TreeMap、TreeSet的关系

    TreeMap和TreeSet是Java种利用搜索树实现的Map和Set,实际上用的是红黑树,红黑树是一颗近似平衡的二叉搜索树,即在二叉搜索树的基础之上+颜色以及红黑树性质。

2. Map和Set的区别与联系

2.1 从接口框架的角度分析

在这里插入图片描述
Map是一个独立的接口,而Set继承自Collection接口。
TreeMap 和 TreeSet 都继承了一个Sorted接口,说明 Tree某某 都是经过排序的,即 Tree某某 都是关于key有序的。

2.2 从存储的模型角度分析【2种模型】

  1. Map中存储的是键值对key-value
  2. Set中只存储了key

3. 关于Map

Map是一个接口类,该类没有继承collection,该类中存储的是<k,v>结构的键值对,并且k一定是唯一的,不能重复。

3.1 Map的注意事项

  1. Map是一个接口,不能直接实例化对象,如果要实例化对象只能实例化其实现类TreeMap或者HashMap。
        Map<Integer, Integer> map1 = new HashMap<>();Map<Integer, Integer> map2 = new TreeMap<>();
  1. Map中存放键值对的键key是唯一的,key不可以重复,但是value可以重复。
  2. 在TreeMap中插入键值队的时候,key不能为空,否则会抛出NPE(空指针异常),但是value可以为空,因为TreeMap中的key是要进行比较的;反而HashMap的key和value都可以为空,因为HashMap不涉及比较。
  3. Map中的key可以全部分离出来,存储到Set中进行访问(因为key不能重复,set是天然的去重),Map中的value可以全部分离出来,存储到Collection的任何一个子集合中(value可能有重复)

3.2 TreeMap 和 HashMap的对比

Map底层结构TreeMapHashMap
底层结构红黑树哈希桶
插入/删除/查找时间复杂度O(log2N)O(1)
是否有序关于key有序无序
线程安全不安全不安全
插入/删除/查找区别需要进行元素比较通过哈希函数计算哈希地址
比较与覆写key必须能够比较,否则会抛出类型转换异常自定义类型需要覆写equals和hashcode方法
应用场景需要key有序的场景下key是否有序不关心,需要更高的时间性能

3.3 Map.Entry<k,v>的用法 (遍历)

Set<Map.Entry <k,v>> entrySet(), 返回所有的key-value映射关系
在这里插入图片描述

        Map<Integer, Integer> map = new TreeMap<>();map.put(1,2);map.put(2,3);map.put(3,6);//key一定是可以进行比较的for(Map.Entry<Integer,Integer> entry : map.entrySet()) {System.out.println(entry.getKey() + ":" + entry.getValue());}

分析:
打印所有的键值对
entrySet():将Map中的键值对放在Set中返回了。
在这里插入图片描述

4. 关于Set

Set与Map主要的不同有2点:
①Set是继承自Collection的接口类
②Set中只存储了Key
Map不能使用迭代器遍历,但是Set可以,因为Set实现了Iterable接口

4.1 Set的注意事项

  1. Set是继承自Collection的一个接口类

  2. Set中只存储了key,并且要求key一定要唯一

  3. Set的底层使用Map来实现的,其使用key与Object的一个默认对象作为键值对插入到Map中
    在这里插入图片描述

  4. Set最大的功能就是对集合中的元素进行去重

  5. TreeSet中不能插入null的key,但是HashSet可以

4.2 TreeSet 和 HashSet的对比

Set底层结构TreeSetHashSet
底层结构红黑树哈希桶
插入/删除/查找时间复杂度O(log2N)O(1)
是否有序关于key有序不一定有序
线程安全不安全不安全
插入/删除/查找区别按照红黑树的特性进行插入和删除通过哈希函数计算哈希地址
比较与覆写key必须能够比较,否则会抛出类型转换异常自定义类型需要覆写equals和hashcode方法
应用场景需要key有序的场景下key是否有序不关心,需要更高的时间性能

4.3 迭代器遍历Set

Iterator< E> iterator() 返回迭代器,可以利用其进行遍历

        Set<Integer> set = new TreeSet<>();set.add(1);set.add(3);set.add(2);set.add(8);set.add(4);Iterator<Integer> iterator = set.iterator();while (iterator.hasNext()) {System.out.print(iterator.next() + " ");}

运行结果:
在这里插入图片描述

5. 哈希表

5.1 哈希函数

  1. 哈希表的效率非常高,查找、删除、插入的时间复杂度都是O(1)。
  2. 理想的搜索方法:不经过任何比较,一次直接从表中得到想要搜索的元素,即一一映射关系。
  3. 哈希方法中使用的转换函数称为哈希函数,构造出来的结构称为哈希表(Hash Table)。
  4. 哈希函数计算出来的地址能均匀分布在整个空间中。

5.2 冲突

  1. 冲突: 不同关键字通过相同哈希函数计算出相同的哈希地址
  2. 冲突的发生是必然的,冲突是不可避免的,只能降低冲突率。
  3. 避免冲突:负载因子调节,其值= 填入表中的元素个数/哈希表的长度,因此可以增加哈希表的长度避免冲突。Java的系统库限制了荷载因子为0.75。

5.3 冲突的解决:开放地址法和链地址法

  1. 开放地址法(闭散列)
    ①线性探测
    ②二次探测
    闭散列最大的缺陷:空间利用率比较低
  2. 链地址法(开散列) 数组+链表+红黑树
    思路:首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于桶一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。
    注意:数组长度>=64,链表长度>=8,就会变成红黑树。

5.4 哈希表与Java集合类的关系

  1. HashMap和HashSet是用哈希表实现的Map和Set。
  2. Java会在冲突链表长度大于一定阈值后,将链表转变成红黑树(搜索树)。
  3. Java中计算哈希值实际上调用的是类的hashcode方法,进行key的相等性比较是调用key的equals方法
  4. 所有自定义类的HashMap的key或者HashSet的值,必须重写hashcode和euqals方法,而且必须做到euqals相等的对象,hashcode一定也是一样的。
  5. 扩容之后要注意每个元素都要重新计算hashcode哈希值。

面试问题:

  1. 问:如果2个对象hashcode一样,equals一定一样吗?
    答:不一定,hashcode一样只能证明我们要找的位置一样,位置一样的下面有很多值,无法确定2个对象的euqals。
  2. 问:如果2个对象equals一样,hashcode一定一样吗?
    答:一定,equals一样则hashcode一定一样。

6. HashMap源码分析

6.1 成员变量

  1. 默认容量:16,最大容量:2的30次方
    在这里插入图片描述
  2. 默认的负载因子:0.75
    在这里插入图片描述
  3. 树化的条件(数组+链表变成红黑树)
    链表长度超过8,数组的容量大于等于64 在这里插入图片描述
  4. 解树的条件(红黑树退化为链表+数组)
    链表的阈值为6的时候
    在这里插入图片描述
  5. table数组的每一个元素是node类型的结点地址
    在这里插入图片描述

6.2 构造方法

  1. 不带参数的构造方法
    负载因子等于默认的负载因子0.75,没有给table数组进行初始化,意味着table数组没有分配内存,数组的大小是0。
    (所以,为什么等会put元素可以put进去?----> 说明在第一次put的时候,会把数组进行初始化为默认容量16)
    在这里插入图片描述
  2. 带2个参数的构造方法
    一个是给定的容量参数,一个是给定的负载因子参数
    在这里插入图片描述
    如果给定的参数容量大于2的30次方,则容量为2的30次方;
    如果给定的参数容量小于0或者给定的负载因子小于0那么就抛异常。
    最后负载因子满足条件直接赋值,但是容量还需要经过tableSizeFor进一步筛选。
    在这里插入图片描述
    tableSizeFor里面:返回最接近目标的一个二次幂整数
    例如:
    传入10:2的3次方=8,2的4次方16,因此返回16。

面试题:调用构造方法给了1000,请问最后哈希数组的长度是多少?
答:1024

在这里插入图片描述

HashMap的最大容量保证是2的n次方,但是如果没有传入一个2的次方怎么办?
答:HashMap会将传入的参数做校验,返回距离传参最近的一个2的n次方的值,例如传入15会初始化为16。

那么,为什么返回二次幂呢?
分析put源码。

6.3 put方法源码

在这里插入图片描述
①先把key给到hash函数中,hash(key),调用hash方法,将引用类型key转换成整数类型
在这里插入图片描述
②hash这个方法中调用了hashcode方法,如果key重写了hashcode方法则会调用自己的hashcode方法,如果没有重写,则会调用Object类的hashcode方法。

h是通过hashcode方法得到的32位的整数,h 异或上 h右移16位
为什么要右移16位?
答:为了更好的均匀分布,低16位和高16位异或,可以让结果更均匀。
在这里插入图片描述

③i = (n - 1) & hash 等价于 n % len,位运算一定是最快的,一定要保证n是2的次幂,这样2个公式才等价。【所以初始化的长度为2的整数次幂】
在这里插入图片描述

相关文章:

Java Map和Set

目录1. 二叉排序树(二叉搜索树)1.1 二叉搜索树的查找1.2 二叉搜索树的插入1.3 二叉搜索树的删除&#xff08;7种情况&#xff09;1.4 二叉搜索树和TreeMap、TreeSet的关系2. Map和Set的区别与联系2.1 从接口框架的角度分析2.2 从存储的模型角度分析【2种模型】3. 关于Map3.1 Ma…...

【C/C++ 数据结构】-八大排序之 冒泡排序快速排序

作者&#xff1a;学Java的冬瓜 博客主页&#xff1a;☀冬瓜的主页&#x1f319; 专栏&#xff1a;【C/C数据结构与算法】 分享&#xff1a;那我便像你一样&#xff0c;永远躲在水面之下&#xff0c;面具之后&#xff01; ——《画江湖之不良人》 主要内容&#xff1a;八大排序选…...

苹果ipa软件下载网站和软件的汇总

随着时间的流逝&#xff0c;做苹果版软件安装包下载网站和软件的渐渐多了起来。 当然&#xff0c;已经关站、停运、下架、倒闭的苹果软件下载网站和软件我就不说了&#xff0c;也不必多说那些关站停运下架倒闭的网站和软件了。 下面我统计介绍的就是苹果软件安装包下载网站和软…...

深度学习-【语义分割】学习笔记4 膨胀卷积(Dilated convolution)

文章目录膨胀卷积为什么需要膨胀卷积gridding effect连续使用三次膨胀卷积——1连续使用三次膨胀卷积——2连续使用三次膨胀卷积——3Understanding Convolution for Semantic Segmentation膨胀卷积 膨胀卷积&#xff0c;又叫空洞卷积。 左边是普通卷积&#xff0c;右边是膨胀…...

【10】SCI易中期刊推荐——工程技术-计算机:人工智能(中科院2区)

🚀🚀🚀NEW!!!SCI易中期刊推荐栏目来啦 ~ 📚🍀 SCI即《科学引文索引》(Science Citation Index, SCI),是1961年由美国科学信息研究所(Institute for Scientific Information, ISI)创办的文献检索工具,创始人是美国著名情报专家尤金加菲尔德(Eugene Garfield…...

模电计算反馈系数,有时候转化为计算电阻分压的问题

模电计算反馈系数&#xff0c;有时候转化为计算电阻分压的问题 如果是电压反馈&#xff0c;F的除数是Uo 如果是电流反馈&#xff0c;F的除数是Io 串联反馈&#xff0c;F的分子是Uf 并联反馈&#xff0c;F的分子是If 点个赞呗&#xff0c;大家一起加油学习&#xff01;...

专治Java底子差,不要再认为泛型就是一对尖括号了

文章目录一、泛型1.1 泛型概述1.2 集合泛型的使用1.2.1 未使用泛型1.2.2 使用泛型1.3 泛型类1.3.1 泛型类的使用1.2.2 泛型类的继承1.4 泛型方法1.5 泛型通配符1.5.1 通配符的使用1&#xff09;参数列表带有泛型2&#xff09;泛型通配符1.5.2 泛型上下边界1.6 泛型的擦除1.6.1 …...

PayPal轮询收款的那些事儿

想必做跨境电商独立站的小伙伴&#xff0c;对于PayPal是再熟悉不过了&#xff0c;PayPal是一个跨国际贸易的支付平台&#xff0c;对于做独立站的朋友来说跨境收款绝大部分都是依赖PayPal以及Stripe条纹了。简单来说PayPal跟国内的支付宝有点类似&#xff0c;但是PayPal它是跨国…...

【Linux】项目自动化构建工具——make/Makefile

目录 1.make与Makefile的关系 Makefile make 项目清理 clean .PHONY 当我们编写一个较大的软件项目时&#xff0c;通常需要将多个源文件编译成可执行程序或库文件。为了简化这个过程&#xff0c;我们可以使用 make 工具和 Makefile 文件。Makefile 文件可以帮助我们自动…...

成本降低90%,OpenAI正式开放ChαtGΡΤ

今天凌晨&#xff0c;OpenAI官方发布ChαtGΡΤ和Whisper的接囗&#xff0c;开发人员现在可以通过API使用最新的文本生成和语音转文本功能。OpenAI称&#xff1a;通过一系列系统级优化&#xff0c;自去年12月以来&#xff0c;ChαtGΡΤ的成本降低了90%&#xff1b;现在OpenAI用…...

hls.js如何播放m3u8文件(实例)?

HLS&#xff08;HTTP Live Streaming&#xff09;是一种视频流传输协议&#xff0c;是苹果推出的适用于iOS与macOS平台的流媒体传输协议。它将视频分割成若干个小段&#xff0c;每个小段大小一般为2~10秒不等&#xff0c;并通过HTTP协议进行传输。通过在每个小段之间插入若干秒…...

大数据平台建设方法论集合

文章目录从0到1建设大数据解决方案大数据集群的方法论数据集成方法论机器学习算法平台方法论BI建设的方法论云原生大数据的方法论低代码数据中台的方法论大数据SRE运维方法论批流一体化建设的方法论数据治理的方法论湖仓一体化建设的方法论数据分析挖掘方法论数字化转型方法论数…...

25- 卷积神经网络(CNN)原理 (TensorFlow系列) (深度学习)

知识要点 卷积神经网络的几个主要结构: 卷积层&#xff08;Convolutions&#xff09;: Valid :不填充&#xff0c;也就是最终大小为卷积后的大小. Same&#xff1a;输出大小与原图大小一致&#xff0c;那么N ​变成了​N2P. padding-零填充. 池化层&#xff08;Subsampli…...

把数组里面数值排成最小的数

问题描述&#xff1a;输入一个正整数数组&#xff0c;将它们连接起来排成一个数&#xff0c;输出能排出的所有数字中最小的一个。例如输入数组{12, 567}&#xff0c;则输出这两个能排成的最小数字12567。请给出解决问题的算法&#xff0c;并证明该算法。 思路&#xff1a;先将…...

云his系统源码 SaaS应用 基于Angular+Nginx+Java+Spring开发

云his系统源码 SaaS应用 功能易扩 统一对外接口管理 一、系统概述&#xff1a; 本套云HIS系统采用主流成熟技术开发&#xff0c;软件结构简洁、代码规范易阅读&#xff0c;SaaS应用&#xff0c;全浏览器访问前后端分离&#xff0c;多服务协同&#xff0c;服务可拆分&#xff…...

小红书场景营销怎么做?场景营销主要模式有哪些

小红书作为新兴媒体领域的佼佼者&#xff0c;凭借着生动&#xff0c;直观&#xff0c;代入感等元素的分享推荐收揽了巨额的流量。但是&#xff0c;随着时代的脚步逐渐加快&#xff0c;发展和变革随之涌来&#xff0c;传统的营销已经无法满足。所以场景营销就出现了。今天就来和…...

c++基础——数组

数组数组是存放相同类型对象的容器&#xff0c;数组中存放的对象没有名字&#xff0c;而是要通过其所在的位置访问。数组的大小是固定的&#xff0c;不能随意改变数组的长度。定义数组数组的声明形如 a[b]&#xff0c;其中&#xff0c;a 是数组的名字&#xff0c;b 是数组中元素…...

odoo15 登录界面的标题自定义

odoo15 登录界面的标题自定义 原代码中查询:<title>Odoo<title> <html> <head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><title>Odoo</title><link rel="shortcut icon…...

【内网服务通过跳板机和公网通信】花生壳内网穿透+Nginx内网转发+mqtt服务搭建

问题&#xff1a;服务不能暴露公网 客户的主机不能连外网&#xff0c;服务MQTT服务部署在内网。记做&#xff1a;p1 (computer 1)堡垒机&#xff08;跳板机&#xff09;可以连外网&#xff0c;内网IP 和 MQTT服务在同一个网段。记做&#xff1a;p2 (computer 2)对他人而言&…...

【多线程常见面试题】

谈谈 volatile关键字的用法? volatile能够保证内存可见性,强制从主内存中读取数据,此时如果有其他线程修改被volatile修饰的变量,可以第一时间读取到最新的值 Java多线程是如何实现数据共享的? JVM把内存分成了这几个区域: 方法区,堆区,栈区,程序计数器&#xff1b; 其中堆区…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...