【数据结构】mapset详解

🍁1. Set系列集合
Set接口是一种不包含重复元素的集合。它继承自Collection接口,所以可以使用Collection所拥有的方法,Set接口的实现类主要有HashSet、LinkedHashSet、TreeSet等,它们各自以不同的方式存储元素,但都遵循Set接口的规定。
- 当你需要确保集合中的元素唯一时。
- 当你不需要保持元素的插入顺序时(除非使用
LinkedHashSet)。- 当你需要元素自然排序或根据自定义排序规则排序时(使用
TreeSet)。

🍁1.1 HashSet
当用HashSet实例化对象时,由于底层结构是哈希表,所以元素是无序的,而TreeSet底层是红黑树,是有序的

由于Set系列集合里面不能有重复的元素,在之前我们也了解到,add方法的返回值是boolean类型的,当遇到重复元素,第二次添加就会添加失败

并且Set集合没有索引的概念,不能通过下标的方式进行遍历打印
和之前一样,没有索引的集合可以通过迭代器,增强for,lambda表达式进行遍历
Iterator<String> it = s1.iterator();while (it.hasNext()){System.out.print(it.next() + " ");}System.out.println();for(String s : s1){System.out.print(s + " ");}System.out.println();s1.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.print(s + " ");}});
🍁1.2 LinkedHashSet
LinkedHashSet底层也是哈希表,但是存取元素的顺序是一致的,因为使用了双向链表记录添加顺序

🍁1.3 TreeSet
TreeSet是基于红黑树实现的,TreeSet中的元素处于排序状态,因此查找、添加、删除和遍历等操作都能以对数时间复杂度进行。但是,向TreeSet中添加的元素必须实现Comparable接口,或者在创建TreeSet时提供一个Comparator对象,以确保元素可以被正确地排序。
排序规则:Integer,Double等数值类型默认按照从小到大的顺序排序,对于字符,字符串类型,按照ASCII码表中的数字进行升排序
接下来演示一下,创建自定义类型的TreeSet
例如:给出一个Student类,要求按照学生的年龄排序
首先创建好Student类之后,需要实现Comparable接口,然后重写compareTo和toString方法
public class Student implements Comparable<Student>{public String name;public int age;public Student(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(Student o) {return this.age - o.age;//this.age表示要添加的元素}
}
this.age表示要添加的元素,所以如果返回值是负数,表示要添加的元素是小的,存左边,如果是0,表示元素已经存在,直接舍弃
public class Text2 {public static void main(String[] args) {Student s1 = new Student("zhang",18);Student s2 = new Student("wang",20);Student s3 = new Student("li",19);TreeSet<Student> treeSet = new TreeSet<>();treeSet.add(s1);treeSet.add(s2);treeSet.add(s3);System.out.println(treeSet);}
}
最终,虽然插入时没有按顺序,由于TreeSet底层是红黑树,所以最终也实现了排序的效果

比较器排序
问题:根据字符串长度比较,长度相同再按字典序比较
//o1:当前要添加的元素//o2:红黑树中已经存在的元素TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return (o1.length() - o2.length()) == 0 ? o1.compareTo(o2) : o1.length() - o2.length();}});ts.add("bbcd");ts.add("abcde");ts.add("abcd");System.out.println(ts);
也就是在创建对象的时候传入比较器进行比较

🍁2. 单列集合的使用场景分析
介绍完Set系列集合之后,我们的单列集合就都学习完了,接下来分析一下这写集合的使用场景
如果集合中元素可重复:使用ArrayList(基于数组)
如果集合中元素可重复并且用到增删操作多余查询:使用LinkedList
如果需要对集合去重:使用HashSet
如果需要在去重的前提下还要保证存取顺序:使用LinkedHashSet
如果需要对集合中的元素进行排序:使用TreeSet
🍁3. Map系列集合
Map系列的集合称为双列集合
1. 双列集合一次存储一对数据,分别为键和值
2. 键不能重复,值可以重复
3. 键和值是一一对应的,每一个键都对应一个值
4. 键+值整体称为键值对,也叫Entry对象
和Set集合类似,Map是顶层接口,底下有这些实现类

以下就是Map集合常用的API

🍁3.1 HashMap
HashMap的底层也是哈希表,和之前的HashSet不同,HashMap中,当插入的key相同时,第二次插入会覆盖原来的value值,同时,如果存储的是自定义类型的对象还需要重写HashCode和equals方法
其他方法就不演示了,下面来介绍一下map的遍历
Map的遍历
键找值:调用keySet方法,获取所有的key,把返回值放在Set集合中,再遍历Set集合,通过get方法获取每一个key的value
//获取所有的键,并放在Set集合中Set<String> set = map.keySet();//遍历set,根据所有的键获取值for(String key:set){int value = map.get(key);System.out.println(key + " = " + value);}
通过键值对对象进行遍历
调用entrySet方法,把所有键值对对象放在Set集合中,再遍历Set集合

可以看出,Entry是Map接口的一个内部接口,所以需要通过Map.Entry的形式调用,也可以直接导入
import java.util.Map.Entry;
就可以省略Map.
遍历时,可以直接打印Entry对象,也可以通过get的方式获取key和value
Set<Map.Entry<String, Integer>> entries = map.entrySet();for(Map.Entry<String,Integer> entry : entries){//System.out.println(entry);String s = entry.getKey();Integer i = entry.getValue();System.out.println(s + " = " + i);}
最后还可以通过lambda的形式遍历
map.forEach(new BiConsumer<String, Integer>() {@Overridepublic void accept(String key, Integer value) {System.out.println(key + " = " + value);}});map.forEach((key, value) -> System.out.println(key + " = " + value));
🍁3.2 LinkedHashMap
和LinkedHashSet一样,LinkedHashMap存储的键是有序的(存储顺序和取出顺序一样)

🍁3.3 TreeMap
TreeMap和TreeSet底层一样,都是红黑树,根据键进行排序,排序规则也是类似的,对于非数值等类型,可以实现Comparable接口,指定比较规则,也可以传入比较器

🍁4. 面试OJ题练习
🍁4.1 随机链表的复制
138. 随机链表的复制

也就是下面这种情况

如果说直接对链表节点进行复制是不可以的,因为题目中要求的是深拷贝,所以说拷贝后的 节点可能和原来的地址不一样
思路:遍历原来的链表,每遍历一次都创建一个新的节点,把原来的节点和拷贝的新节点的映射关系使用map存储起来,再通过get方法得到节点,再连接next和random

public Node copyRandomList(Node head) {Map<Node, Node> map = new LinkedHashMap<>();Node cur = head;while (cur != null) {Node copy = new Node(cur.val);map.put(cur, copy);cur = cur.next;}/*cur = head;while (cur != null) {map.get(cur).next = map.get(cur.next);map.get(cur).random = map.get(cur.random);cur = cur.next;}*/Set<Node> keySet = map.keySet();for (Node curNode : keySet) {map.get(curNode).next = map.get(curNode.next);map.get(curNode).random = map.get(curNode.random);}return map.get(head);}
🍁4.2 宝石与石头
771. 宝石与石头

这一题就可以很好的利用Set集合元素不能重复的特性了,如果不用Set集合,把全部元素异或一遍就可以找到了,而且速度更快,这里只是为了练习一下Set集合的使用,只需要把jewels存一个set,再遍历stones,判断是否有set集合里的元素即可
public class Text {public static void main(String[] args) {String jewels = "aA";String stones = "aAABBBBB";System.out.println(numJewelsInStones(jewels, stones));}public static int numJewelsInStones(String jewels, String stones) {Set<Character> set = new HashSet<>();for (int i = 0; i < jewels.length(); i++) {set.add(jewels.charAt(i));}int cnt = 0;for (int i = 0; i < stones.length(); i++) {if (set.contains(stones.charAt(i))) {cnt++;}}return cnt;}
}
🍁4.3 前k个高频单词
692. 前K个高频单词

思路:前k个高频词,就是经典的topk问题,根据之前我们学到的,就是用小根堆解决,首先统计一下每个单词出现的频率,并通过map存储它们的映射关系,接着创建小根堆,套用之前的模板解决
public List<String> topKFrequent(String[] words, int k) {Map<String, Integer> map = new HashMap<>();//统计单词个数并存入mapfor (String s : words) {if (map.get(s) == null) {map.put(s, 1);} else {int val = map.get(s);map.put(s, ++val);}}//创建根据map的value创建小根堆PriorityQueue<Map.Entry<String, Integer>> minHeap = new PriorityQueue<>(new Comparator<Map.Entry<String, Integer>>() {@Overridepublic int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {//相同时根据key创建大根堆,最后反转的时候就可以把字典序靠前的排到前面了if (o1.getValue().compareTo(o2.getValue()) == 0) {return o2.getKey().compareTo(o1.getKey());}return o1.getValue().compareTo(o2.getValue());}});//根据之前讲解的topk问题解决for (Map.Entry<String, Integer> entry : map.entrySet()) {//先把前K个元素加入大根堆if (minHeap.size() < k) {minHeap.offer(entry);} else {Map.Entry<String, Integer> top = minHeap.peek();//堆顶元素频率小于后面的if (top.getValue().compareTo(entry.getValue()) < 0) {minHeap.poll();minHeap.offer(entry);} else if (top.getValue().compareTo(entry.getValue()) == 0) {//堆顶元素等于后面时,堆顶的key字典序大于后面的if (top.getKey().compareTo(entry.getKey()) > 0) {minHeap.poll();minHeap.offer(entry);}}}}ArrayList<String> ans = new ArrayList<>();//把key存入ArrayListfor (int i = 0; i < k; i++) {ans.add(minHeap.poll().getKey());}//题目要求出现频率由高到低,进行翻转Collections.reverse(ans);return ans;}

相关文章:
【数据结构】mapset详解
🍁1. Set系列集合 Set接口是一种不包含重复元素的集合。它继承自Collection接口,所以可以使用Collection所拥有的方法,Set接口的实现类主要有HashSet、LinkedHashSet、TreeSet等,它们各自以不同的方式存储元素,但都遵…...
数据结构(邓俊辉)学习笔记】词典 02—— 散列函数
文章目录 1. 冲突难免2. 何为优劣3. 整除留余4. 以禅为师5. M A D6. 平方取中7. 折叠汇总8. 伪随机数9. 多项式10. Vorldmort 1. 冲突难免 好,接下来的这一节我们就来介绍散列策略中的第一项,也是最重要的技术,散列函数的设计与定制。 在上…...
Python学习(1):使用Python的Dask库实现并行计算
目录 一、Dask介绍 二、使用说明 安装 三、测试 1、单个文件中实现功能 2、运行多个可执行文件 最近在写并行计算相关部分,用到了python的Dask库。 Dask官网:Dask | Scale the Python tools you love 一、Dask介绍 Dask是一个灵活的并行和分布式…...
数据结构 - 哈希表
文章目录 前言一、哈希思想二、哈希表概念三、哈希函数1、哈希函数设计原则2、常用的哈希函数 四、哈希冲突1、什么是哈希冲突2、解决哈希冲突闭散列开散列 五、哈希表的性能分析时间复杂度分析空间复杂度分析 前言 一、哈希思想 哈希思想(Hashing)是计…...
电商选品这几点没做好,等于放弃80%的流量!
在竞争激烈的电商领域,选品是决定店铺命运的核心环节。到底是哪些关键要点能够帮助我们在选品时抢占流量高地,稳步出单呢? 一、深入了解市场需求 选品的第一步是对市场进行深入调研。要关注当前的消费趋势、热门品类以及潜在的需求缺口。通…...
【教程】最新可用!Docker国内镜像源列表
转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~ 目录 镜像加速器地址 用法示例 一、自动配置地址 二、配置单次地址 镜像加速器地址 Docker镜像加速站https://hub.uuuadc.top/docker.1panel.live…...
使用RabbitMQ在Spring Boot入门实现简单的消息的发送与接收
文章目录 要引入spring-boot-starter-amqp依赖才能开始后续操作 1. 配置RabbitMQ地址2. 编写消息发送测试类3. 实现消息接收 在本文中,我们将介绍如何在Spring Boot应用中使用RabbitMQ实现消息的发送与接收。我们将创建两个服务,一个用于发送消息&#x…...
基于物联网的水质监测系统设计与实现:React前端、Node.js后端与TCP/IP协议的云平台集成(代码示例)
一、项目概述 随着环境保护意识的增强,水质监测在水资源管理和污染防治中变得尤为重要。本项目旨在设计一个基于物联网的水质监测系统,能够实时监测水中的pH值、溶解氧、电导率和浊度等参数,并将数据传输至云端,以便进行分析和可…...
Vcpkg安装指定版本包或自定义安装包
在使用 vcpkg 安装特定版本的包或自定义包时,你可以按照以下步骤进行操作: 安装特定版本的包 列出可用的版本: 使用以下命令列出特定包的所有可用版本: vcpkg search <package-name>安装特定版本: 使用 vcpkg …...
【C++深度探索】红黑树实现Set与Map的封装
🔥 个人主页:大耳朵土土垚 🔥 所属专栏:C从入门至进阶 这里将会不定期更新有关C/C的内容,欢迎大家点赞,收藏,评论🥳🥳🎉🎉🎉 文章目录…...
终于有人把客户成功讲明白了
作者:沈建明 对ToB企业来说,只有客户成功才能带来持久增长,在SaaS企业下行大背景下,客户成功是唯一的救命稻草。大家是不是都听过这样的说法? ToB和SaaS企业的老客户贡献对于企业至关重要。因为获取新客户的成本是留…...
[新械专栏] 肾动脉射频消融仪及一次性使用网状肾动脉射频消融导管获批上市
近日,国家药品监督管理局批准了上海魅丽纬叶医疗科技有限公司“肾动脉射频消融仪”和“一次性使用网状肾动脉射频消融导管”两个创新产品注册申请。 肾动脉射频消融仪由主机、脚踏开关、主机连接线、中性电极连接线以及电源线组成。一次性使用网状肾动脉射频消融导…...
leetcode-119-杨辉三角II
原理: 1、初始化每行一维数组nums[1]; 2、从第2行开始,在nums的头插入0(因为杨辉三角每行的第一个1相当于是上一行的1与其前面的0相加之和)后进行相加操作。 代码:...
【第八节】python正则表达式
目录 一、python中的re模块 1.1 基本匹配和搜索 1.2 替换和分割 1.3 编译正则表达式 二、正则表达式对象 2.1 re.RegexObject 和 re.MatchObject 2.2 正则表达式修饰符 - 可选标志 2.3 正则表达式模式 2.4 正则表达式实例 一、python中的re模块 正则表达式是一种独特的…...
三大浏览器Google Chrome、Edge、Firefox内存占用对比
问题 Chrome、Edg、Firefox三家究竟谁的占用少 结论 打开一个页面内存占用 Firefox>Edge>Chrome 打开打量页面内存占用 Firefox>Chrome>Edge 从监视器可以看到Edge增加一个页面增加一个页面不到100M而其它浏览器需要150M左右;Firefox浏览器主线程内存占用800M比…...
【wiki知识库】08.添加用户登录功能--后端SpringBoot部分
目录 一、今日目标 二、SpringBoot后端实现 2.1 新增UserLoginParam 2.2 修改UserController 2.3 UserServiceImpl代码 2.4 创建用户上下文工具类 2.5 通过token校验用户(重要) 2.6 创建WebMvcConfig 2.7 用户权限校验拦截器 一、今日目标 上篇…...
vue中nextTick的作用
nextTick是Vue.js提供的一个非常有用的方法,其主要作用是在DOM更新之后执行延迟回调函数。以下是nextTick的具体作用及其实现原理的详细解析: nextTick的作用 确保DOM更新完成: 当Vue实例的数据发生变化时,Vue会异步地更新DOM。…...
计算机网络面试-核心概念-问题理解
目录 1.计算机网络OSI协议七层结构功能分别是什么?如何理解这些功能 2.物理层、数据链路层、网络层、传输层和应用层,这五个层之间功能的关系,或者说是否存在协调关系 3. 数据链路层功能理解 4.MAC地址和以太网协议 5.以太网协议中的CSMA…...
go语言创建协程
前言 Go 语言中,协程是通过 go 关键字来创建的,这使得 Go 语言成为实现并发程序的一个非常直观和强大的工具。Go 运行时管理着协程,这些协程在内部被称为 goroutine。 协程(goroutines)本身是轻量级的线程,…...
RabbitMQ之基于注解声明队列交换机:使用@RabbitListener实现消息监听
文章目录 什么是RabbitListener?队列和交换机的基本概念使用RabbitListener注解声明队列和交换机代码解析1. QueueBinding2. 消费者方法 运行原理应用场景总结 在现代的微服务架构中,消息队列是一种重要的异步通信机制。RabbitMQ作为一种流行的消息代理软…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...

