Map和Set知识点

2023-11-10

目录

1. Map的使用

 1.1 Map常用方法

2. Set的使用

2.1 Set常见方法

3. 二叉搜索树(BST)

4. 哈希表

4.1 哈希冲突

4.2 避免哈希冲突

4.2.1 哈希函数的设计

 4.2.2 负载因子调节

4.3 解决哈希冲突

4.3.1 开散列(哈希桶)(重点掌握)

4.3.2 闭散列(开放定址法)


1. Map的使用

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

 1.1 Map常用方法

返回 key 对应的 value
map.get(key);
返回 key 对应的 valuekey 不存在,返回默认值
map.getOrDefault(key, map.get(key, 0) + 1);
设置 key 对应的 value
map.put(key,value);
删除 key 对应的映射关系
map.remove(key);
返回所有 key 的不重复集合
Set<key> keySet();
遍历map集合
for(Map.Entry<Integer, Integer> entry : map.entrySet()) {
     if(entry.getValue() == 1) {
         return entry.getKey();
     }
}
判断是否包含 key
if(containsKey(key)) {}

判断是否包含 value

if(containsKey(value)) {}

注意:

1. Map 是一个接口, 不能直接实例化对象 ,如果 要实例化对象只能实例化其实现类 TreeMap 或者 HashMap。
2. Map 中存放键值对的 Key 是唯一的, value是可以重复的
3. Map 中插入键值对时, key不能为空 ,否则就会抛 NullPointerException 异常 ,但是 value可以为空。
4. Map 中的 Key 可以全部分离出来,存储到 Set 来进行访问 ( 因为 Key 不能重复 )
5. Map 中的 value 可以全部分离出来,存储在 Collection 的任何一个子集合中 (value 可能有重复 )
6. Map 中键值对的 Key 不能直接修改, value 可以修改,如果要修改 key ,只能先将该 key 删除掉,然后再来进行重新插入。
Map底层结构 TreeMap HashMap
底层结构 红黑树 哈希桶
插入/删除/查找时间
复杂度
O(logN)
                               
是否有序 关于Key有序 无序
线程安全 不安全 不安全
插入/删除/查找区别 需要进行元素比较 通过哈希函数计算哈希地址
比较与覆写 key必须能够比较,否则会抛出
ClassCastException异常
自定义类型需要覆写equals和
hashCode方法
应用场景 需要Key有序场景下 Key是否有序不关心,需要更高的
时间性能

2. Set的使用

SetMap主要的不同有两点:Set是继承自Collection的接口类Set中只存储了Key

2.1 Set常见方法

添加元素,但重复元素不会被添加成功
set.add(x);
清空集合
set.clear();
判断 x是否在集合中
if(set.contains(x)) {}
删除集合中的 x
boolean remove(x)
返回set中元素的个数
int size = set.size();

检测set是否为空,空返回true,否则返回false  

if(set.isEmpty()) {}

set中的元素转换为数组返回

Object[] toArray()

 集合c中的元素是否在set中全部存在,是返回true,否则返回 false

boolean containsAll(Collection<?> c)

注意:

1. Set是继承自Collection的一个接口类。
2. Set中只存储了key,并且要求key一定要唯一。
3. Set的底层是使用Map来实现的。
4. Set最大的功能就是对集合中的元素进行去重。
5. 实现Set接口的常用类有TreeSet和HashSet,还有一个LinkedHashSet(是在HashSet的基础上维护了一个双向链表来记录元素的插入次序)
6. Set中的Key不能修改,如果要修改,先将原来的删除掉,然后再重新插入
7. Set中不能插入nullkey
Set底层结构 TreeSet HashSet
底层结构 红黑树 哈希桶
插入/删除/查找时间
复杂度
O(logN)
是否有序 关于Key有序 不一定有序
线程安全 不安全 不安全
插入/删除/查找区别 按照红黑树的特性来进行插入和删除 1. 先计算key哈希地址 2. 然后进行
插入和删除
比较与覆写 key必须能够比较,否则会抛出
ClassCastException异常
自定义类型需要覆写equals和
hashCode方法
应用场景 需要Key有序场景下 Key是否有序不关心,需要更高的
时间性能

3. 二叉搜索树(BST)

二叉搜索树又称二叉排序树,它或者是一棵空树 ,或者是具有以下性质的二叉树 :
1. 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
2. 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
3. 它的左右子树也分别为二叉搜索树

1. 中序遍历得到的数组是升序的 

2. 不一定是个完全二叉树

4. 哈希表

顺序结构以及平衡树 中,元素关键码与其存储位置之间没有对应的关系,因此在 查找一个元素时,必须要经过关键 码的多次比较 顺序查找时间复杂度为O(N) 平衡树中为树的高度,即O( logN) ,搜索的效率取决于搜索过程中元素的比较次数。
理想的搜索方法:可以 不经过任何比较,一次直接从表中得到要搜索的元素 如果构造一种存储结构,通过某种函 (hashFunc) 使 元素的存储位置 与它的 关键码之间 能够建立一一映射的关系,那么在查找时通过该函数可以很快 找到该元素
1. 插入元素 :根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放。
2.  搜索元素: 对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若 关键码相等,则搜索成功。
该方式即为 哈希(散列)方法 哈希方法中使用的转换函数称为 哈希(散列)函数 ,构造出来的结构称为 哈希表 (Hash Table)( 或者称散列表 )
例如:数据集合 {1 7 6 4 5 9}
哈希函数设置为: hash(key) = key % capacity ; capacity 为存储元素底层空间总的大小。

 

用该方法进行搜索不必进行多次关键码的比较,因此搜索的速度比较快

4.1 哈希冲突

key1 != key2 , hash(key1) == hash(key2)
不同关键字通过相同哈 希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞

4.2 避免哈希冲突

引起起哈希冲突的一个原因可能是:哈希函数设计不够合理

4.2.1 哈希函数的设计

key 为整型的时候哈希函数的设计:取模一般来说,取模使用素数)

哈希函数设计的三个要求:

1. 一致性:无论经过多少次的哈希函数运算,key不变,hash值不变

2. 高效性:哈希函数的运算不能太耗时,尽量可以立即计算得出

3. 均匀性:比如说,通过哈希函数运算之后,得到的值分布在【0,1】区间上,这就不均匀

 4.2.2 负载因子调节

 负载因子 = 元素个数 / 数组长度

当元素个数 >= 数组长度 * 负载因子,此时认为哈希表中冲突比较多。

负载因子越大,冲突几率越大,效率越低。

负载因子越小,冲突几率越小,但浪费空间。

4.3 解决哈希冲突

当发生哈希冲突时,最常见的两种处理方式:

1. 开散列(拉链法 / 链地址法)

2. 闭散列

4.3.1 开散列(哈希桶)(重点掌握)

开散列法又叫链地址法 (拉链法)

首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中

 大部分工程都使用链地址法来解决哈希冲突问题。

链表的长度不会很长,控制在常量范围内。

JDK1.8之后,当链表的长度超过8,这个链表就会变成红黑树,时间复杂从O(N) 变成O(logN)

性能:

虽然哈希表一直在和冲突做斗争,但在实际使用过程中,我们认为哈希表的冲突率是不高的,冲突个数是可控的, 也就是每个桶中的链表的长度是一个常数,所以,通常意义下,我们认为哈希表的插入/删除/查找时间复杂度是 O(1)  


public class HashBuck {
    static class Node {
        public int key;
        public int val;
        public Node next;

        public Node(int key, int val) {
            this.key =key;
            this.val = val;
        }
    }
    public Node[] array;
    public int usedSize;

    public static final double DEFAULT_LOADFACTOR = 0.75;

    public HashBuck(){
        this.array = new Node[10];
    }

    public void put(int key, int val) {
        //1. 找到key所在的位置
        int index = key % this.array.length;
        //2. 遍历这个下标的链表,看是不是有相同的key(更新val)
        Node cur = array[index];
        while(cur != null) {
            if(cur.key == key) {
                cur.val = val;
                return;
            }
            cur = cur.next;
        }
        //3. 没有这个key元素,头插法
        Node node = new Node(key,val);
        node.next = array[index];
        array[index] = node;
        this.usedSize++;

        //4. 插入元素成功之后,检查当前散列表的负载因子
        if(loadFactor() > DEFAULT_LOADFACTOR) {
            resize(); //负载因子大于0,75  扩容
            // 注意:如果扩容数组,那么数组里面的每个链表上的元素都要重新进行哈希

        }
    }

    /**
     * 扩容
     */
    private void resize() {
        Node[] newArray = new Node[array.length * 2];
        for (int i = 0; i < array.length; i++) {  //遍历原来的数组
            Node cur = array[i];
            while(cur != null) {
                int index = cur.key % newArray.length; // 获取新的下标
                //把cur这个节点以头插或者尾插的形式,插入到新的数组对应的链表下标中
                Node curNext = cur.next;
                cur.next = newArray[index];
                newArray[index] = cur;
                cur = curNext;
            }
        }
    }

    private double loadFactor() {
        return 1.0 * usedSize / array.length;
    }
    /**
     * 根据key获取value值
     * @param key
     * @return
     */
    public int get(int key) {
        //1. 找到key所在的位置
        int index = key % this.array.length;
        //2. 遍历这个下标的链表,看是不是有相同的key(更新val)
        Node cur = array[index];
        while(cur != null) {
            if(cur.key == key) {
                return cur.val;
            }
            cur = cur.next;
        }
        return -1;
    }
}

4.3.2 闭散列(开放定址法

闭散列:也叫 开放定址法 ,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以 key 存放到冲突位置中的 下一个 空位置中去。

如何寻找下一个空位置呢?

1. 线性探测
例如:数据集合 {1 7 6 4 5 9}
哈希函数设置为: hash(key) = key % capacity ; capacity 为存储元素底层空间总的大小。
现在需要插入元素 44 ,先通过哈希函数计算哈希地址,下标为 4 ,因此 44 理论上应该插在该
位置,但是该位置已经放了值为 4 的元素,即发生哈希冲突。
线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。

会发现此时,把冲突的元素都放在一块。 

 2. 二次探测

线性探测的缺陷是产生冲突的数据堆积在一块,这与其找下一个空位置有关系,因为找空位置的方式就是挨着往后逐个去找,因此二次探测为了避免该问题,找下一个空位置的方法为:

 i 表示第几次冲突

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Map和Set知识点 的相关文章

  • 在 Java 中连接和使用 Cassandra

    我已经阅读了一些关于 Cassandra 是什么以及它可以做什么的教程 但我的问题是如何在 Java 中与 Cassandra 交互 教程会很好 如果可能的话 有人可以告诉我是否应该使用 Thrift 还是 Hector 哪一个更好以及为什
  • Play框架运行应用程序问题

    每当我尝试运行使用以下命令创建的新 Web 应用程序时 我都会收到以下错误Play http www playframework org Error occurred during initialization of VM Could no
  • Java JDBC:更改表

    我希望对此表进行以下修改 添加 状态列 varchar 20 日期列 时间戳 我不确定该怎么做 String createTable Create table aircraft aircraftNumber int airLineCompa
  • 如何找到给定字符串的最长重复子串

    我是java新手 我被分配寻找字符串的最长子字符串 我在网上研究 似乎解决这个问题的好方法是实现后缀树 请告诉我如何做到这一点或者您是否有任何其他解决方案 请记住 这应该是在 Java 知识水平较低的情况下完成的 提前致谢 附 测试仪字符串
  • 给定两个 SSH2 密钥,我如何检查它们是否属于 Java 中的同一密钥对?

    我正在尝试找到一种方法来验证两个 SSH2 密钥 一个私有密钥和一个公共密钥 是否属于同一密钥对 我用过JSch http www jcraft com jsch 用于加载和解析私钥 更新 可以显示如何从私钥 SSH2 RSA 重新生成公钥
  • JAXb、Hibernate 和 beans

    目前我正在开发一个使用 Spring Web 服务 hibernate 和 JAXb 的项目 1 我已经使用IDE hibernate代码生成 生成了hibernate bean 2 另外 我已经使用maven编译器生成了jaxb bean
  • INSERT..RETURNING 在 JOOQ 中不起作用

    我有一个 MariaDB 数据库 我正在尝试在表中插入一行users 它有一个生成的id我想在插入后得到它 我见过this http www jooq org doc 3 8 manual sql building sql statemen
  • 反射找不到对象子类型

    我试图通过使用反射来获取包中的所有类 当我使用具体类的代码 本例中为 A 时 它可以工作并打印子类信息 B 扩展 A 因此它打印 B 信息 但是当我将它与对象类一起使用时 它不起作用 我该如何修复它 这段代码的工作原理 Reflection
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • 操作错误不会显示在 JSP 上

    我尝试在 Action 类中添加操作错误并将其打印在 JSP 页面上 当发生异常时 它将进入 catch 块并在控制台中打印 插入异常时出错 请联系管理员 在 catch 块中 我添加了它addActionError 我尝试在jsp页面中打
  • 斯坦福 NLP - 处理文件列表时 OpenIE 内存不足

    我正在尝试使用斯坦福 CoreNLP 中的 OpenIE 工具从多个文件中提取信息 当多个文件 而不是一个 传递到输入时 它会给出内存不足错误 All files have been queued awaiting termination
  • 如何在PreferenceActivity中添加工具栏

    我已经使用首选项创建了应用程序设置 但我注意到 我的 PreferenceActivity 中没有工具栏 如何将工具栏添加到我的 PreferenceActivity 中 My code 我的 pref xml
  • Java按日期升序对列表对象进行排序[重复]

    这个问题在这里已经有答案了 我想按一个参数对对象列表进行排序 其日期格式为 YYYY MM DD HH mm 按升序排列 我找不到正确的解决方案 在 python 中使用 lambda 很容易对其进行排序 但在 Java 中我遇到了问题 f
  • Java TestNG 与跨多个测试的数据驱动测试

    我正在电子商务平台中测试一系列商店 每个商店都有一系列属性 我正在考虑对其进行自动化测试 是否有可能有一个数据提供者在整个测试套件中提供数据 而不仅仅是 TestNG 中的测试 我尝试不使用 testNG xml 文件作为机制 因为这些属性
  • 在两个活动之间传输数据[重复]

    这个问题在这里已经有答案了 我正在尝试在两个不同的活动之间发送和接收数据 我在这个网站上看到了一些其他问题 但没有任何问题涉及保留头等舱的状态 例如 如果我想从 A 类发送一个整数 X 到 B 类 然后对整数 X 进行一些操作 然后将其发送
  • 在 Mac 上正确运行基于 SWT 的跨平台 jar

    我一直致力于一个基于 SWT 的项目 该项目旨在部署为 Java Web Start 从而可以在多个平台上使用 到目前为止 我已经成功解决了由于 SWT 依赖的系统特定库而出现的导出问题 请参阅相关thread https stackove
  • 仅将 char[] 的一部分复制到 String 中

    我有一个数组 char ch 我的问题如下 如何将 ch 2 到 ch 7 的值合并到字符串中 我想在不循环 char 数组的情况下实现这一点 有什么建议么 感谢您花时间回答我的问题 Use new String value offset
  • 声明的包“”与预期的包不匹配

    我可以编译并运行我的代码 但 VSCode 中始终显示错误 早些时候有一个弹出窗口 我不记得是什么了 我点击了 全局应用 从那以后一直是这样 Output is there but so is the error The declared
  • java.lang.IllegalStateException:驱动程序可执行文件的路径必须由 webdriver.chrome.driver 系统属性设置 - Similiar 不回答

    尝试学习 Selenium 我打开了类似的问题 但似乎没有任何帮助 我的代码 package seleniumPractice import org openqa selenium WebDriver import org openqa s
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两

随机推荐

  • linux的oops界面,Linux编程时遇到Oops提示该如何排查?

    用于表示函数的调用关系 通过这段信息我们可以知道 函数的整个执行流程 知道它的函数调用关系 最后整理出来的函数执行流程如下 本文引用地址 http www eepw com cn article 201811 395128 htm 从中我们
  • 基于LiDAR的目标检测算法

    自动驾驶中 激光雷达点云如何做特征表达 基于激光雷达点云 lidar 的目标检测方法之BEV 基于激光雷达点云 lidar 的目标检测方法之camera range view 基于激光雷达点云 lidar 的目标检测方法之point wis
  • VueTouchKeyboard——一个模拟键盘

    功能需求 封装一个带有设计好的样式的输入组件 输入方式为模拟的数字键盘 键盘组件为VueTouchKeyboard 下载方式如下 npm install vue touch keyboard save image png 封装的输入组件 模
  • 素数的求解方法:

    一 朴素判断素数算法 就判断素数而言 事实上是非常简单的了 根据定义 判断一个整数n是否是素数 只需要去判断在整数区间 2 n 1 之内 是否具有某个数m 使得n m 0 代码可以这么写 int isPrime int n int i fo
  • Arduino IDE 烧录 ESP8266教程

    Arduino IDE for ESP8266教程 原出处 http www windworkshop cn p 758 ESP8266是现在性价比不错的Wifi模块 用了一块ESP8266 01之后感觉还行 用在数据采集器上表现还是不错的
  • IDEA中build path导入外包jar 包的方法

    小编今天需要在IDEA中导入外部jar包 由于在eclipse中可以在外部jar包上直接右键 build path 然后点击add to Build Path 就成功导入了 可惜IDEA并不是如此 有点小苦恼 接下来 小编就带大家操作 ID
  • 分解命令行字符串为argc和argv

    有时候需要用空格把一个命令行参数字符串分解为参数个数和参数指针 就是常见的c语言main 函数入口argc argv 这里采用strtok 函数可以很方便的做到 char strtok char str const char delim 用
  • 关于取消开机bois密码的方法

    有时在不小心设置了bois密码 导致每次开机都需要输入密码 显得十分麻烦 如何取消bois密码呢 经过查阅各种资料 有两种2情况 分别是 知道bois密码 和不知道bois密码 大部分的文章中都讲到的是忘记bois密码的方式 这边将一下 知
  • 点云边界提取方法总结

    目录 经纬线扫描法 网格划分法 法线估计法 alpha shapes算法 原始点云 经纬线扫描法 经纬线扫描法的基本思想是 将经过坐标变换后的二维数据点集按照 x值的大小排序后存储在一个链表中 在二维平面建立点集的最小包围盒并分别计算出 x
  • 用Python创造无穷可能,独家教你如何开发赚钱项目!

    前言 Python都可以做哪些副业 1 兼职处理数据Excel整理数据功能虽然很强大 但在Python面前 曾经统治职场的它也的败下阵来 因为Python在搜集数据整理分析数据的过程中更加便捷 通过几行代码还可以实现自动化操作 如果你学会P
  • Spring注解式注入依赖bean优先级

    使用注解的方式注入bean实例 在两年前的开发中 还经常看到 Resource注解 这个注解是基于JSR250标准的 现在基本很少看到使用了 取而代之的是 Autowired注解 也是官方推荐的 随着spring boot的出现 很多开发小
  • Windows7访问Samba,总是提示 未知的用户名或错误密码

    这个问题纠结了好几天 在网上也查了好些资料都没有解决 现在终于解决了 必须要分享出来 环境配置 PC1 Linux Mint 19 2 在此电脑上配置Samba服务 我为了方便 是通过Mint的一个Samba插件配置的 PC2 Win7 6
  • 民安智库(北京第三方窗口测评)开展汽车消费者焦点小组座谈会调查

    民安智库近日开展了一场汽车消费者焦点小组座谈会 旨在深入了解目标消费者对汽车功能的需求和消费习惯 为汽车企业提供有针对性的解决方案 在焦点小组座谈会中 民安智库公司 第三方市容环境指数测评 邀请了一群具有代表性的汽车消费者作为参与者 他们来
  • 【计算机毕业设计】231论文投稿系统

    一 系统截图 需要演示视频可以私聊 本文介绍了论文投稿系统的开发全过程 通过分析企业对于论文投稿系统的需求 创建了一个计算机管理论文投稿系统的方案 文章介绍了论文投稿系统的系统分析部分 包括可行性分析等 系统设计部分主要介绍了系统功能设计和
  • 4-2 张量的数据运算

    张量数学运算主要有 标量运算 向量运算 矩阵运算 以及使用非常强大而灵活的爱因斯坦求和函数torch einsum 重难点 进行任意维的张量运算 此外还会介绍张量运算的广播机制 一 标量运算 操作的张量至少是0维 张量的数学运算符可以分为标
  • Java基础-继承

    子类继承父类后构造器的特点 子类中所有的构造器默认都会先访问父类中的无参的构造器 再执行自己 为什么 子类在初始化的时候 有可能会使用到父类中的数据 如果父类没有完成初始化 子类将无法使用父类的数据 子类初始化之前 一定要调用父类构造器先完
  • Topaz Video Enhance AI 2.3.0 for Mac专业级AI视频增强软件,详细图文安装教程。

    Topaz Video Enhance AI 2 3 0 for Mac是世界一流的AI视频质量增强软件 站长亲测有效 使用突破性的 AI 技术进行令人惊叹的视频放大 Topaz Video Enhance AI 接受了数千个视频的训练并结
  • IDEA常用插件介绍

    前言 插件名为笔者自用的IDEA2019 3 5所能搜索到的 若新版IDEA未能搜索到 可用括号内的插件名替代 一 Lombok 新版IDEA自带 Lombok能通过注解的方式 在编译时自动为属性生成构造器 getter setter eq
  • LeetCode-替换空格

    创建一个新的string 一边遍历原字符串的每一个字符 一边往新的字符串中写入 遇到空格替换为 20即可 class Solution public string replaceSpaces string str string res fo
  • Map和Set知识点

    目录 1 Map的使用 1 1 Map常用方法 2 Set的使用 2 1 Set常见方法 3 二叉搜索树 BST 4 哈希表 4 1 哈希冲突 4 2 避免哈希冲突 4 2 1 哈希函数的设计 4 2 2 负载因子调节 4 3 解决哈希冲突