【数据结构】Map与Set

news2024/9/21 14:47:28

前言

    前两篇文章我们研究了二叉搜索树与哈希表的结构与特点,他们二者是Map与Set这两个接口实现的底层结构,他们利用了搜索树与哈希表查找效率高这一特点,是一种专门用来进行搜索操作的容器或数据结构。本篇文章就让我们一起来梳理这两个接口的特性与用法吧

58d60bbf89ce4be698240c1474f4da73.png

在介绍这两个接口前先说明一下Key-value模型吧:

    一般把搜索的数据称为关键字(Key),和关键字对应的称为值(Value),将其称之为Key-value的键值对,所以模型会有两种:
1. key 模型,比如:
有一个英文词典,快速查找一个单词是否在词典中快速查找某个名字在不在通讯录中
2. Key-Value 模型,比如:
统计文件中每个单词出现的次数,统计结果是每个单词都有与其对应的次数:<单词,单词出现的次数>梁山好汉的江湖绰号:每个好汉都有自己的江湖绰号
Map 中存储的就是 key-value 的键值对, Set 中只存储了 Key
 
 

一、Map

3784d2b8c38f434db7f6ce60bc674457.png

Map 是一个接口类,该类没有继承自 Collection ,该类中存储的是 <K,V> 结构的键值对,并且 K 一定是唯一的,不 能重复
Map.Entry<K, V> 是 Map 内部实现的用来存放 <key, value> 键值对映射关系的内部类,该内部类中主要提供了<key, value>的获取,value的设置以及Key的比较方式。
 
方法解释
K getKey()
返回 entry 中的 key
V getValue()
返回 entry 中的 value
V setValue(V value)
将键值对中的value替换为指定value

 

 
 
 
 
 
 
 
注意:Map.Entry<K,V> 并没有提供设置 Key 的方法
Map 的常用方法说明
aad74e44e2cc4ccca5b53e182933d846.png
 
注意:
1. Map 是一个接口,不能直接实例化对象,如果 要实例化对象只能实例化其实现类 TreeMap 或者 HashMap
2. Map 中存放键值对的 Key 是唯一的, value 是可以重复的
3. 在 TreeMap 中插入键值对时, key 不能为空,否则就会抛 NullPointerException 异常,value可以为空。但是HashMap的key和value都可以为空。
4. Map 中的 Key 可以全部分离出来,存储到 Set 来进行访问(因为Key不能重复)。
5. Map 中的 value 可以全部分离出来,存储在 Collection 的任何一个子集合中(value可能有重复)。
6. Map中键值对的Key不能直接修改,value可以修改,如果要修改key,只能先将该key删除掉,然后再来进行重新插入。
8446713306834a369d27a58cf936962a.png
 
HashMap的简单实现:
public class HashBuck2<K,V> {
    static class Node<K,V> {
        public K key;
        public V val;
        public Node<K,V> next;
        public Node(K key,V val) {
            this.key = key;
            this.val = val;
        }
    }

    public Node<K,V>[] array = (Node<K,V>[])new Node[10];
    //public Node<K,V>[] array = new Node<K,V>[10];

    public int usedSize;

    public double loadFactor = 0.75;

    public void put(K key,V val) {
        int hash = key.hashCode();
        int index = hash % array.length;
        Node<K,V> cur = array[index];
        //1. 遍历当前链表 是否存在当前值
        while (cur != null) {
            if(cur.key.equals(key)) {
                cur.val = val;
                return;
            }
            cur = cur.next;
        }
        //2. 说明 没有当前值,此时进行 头插
        Node<K,V> node = new Node<K,V>(key,val);
        node.next = array[index];
        array[index] = node;
        usedSize++;
    }

    public V get(K key) {
        int hash = key.hashCode();
        int index = hash % array.length;
        Node<K,V> cur = array[index];
        //1. 遍历当前链表 是否存在当前值
        while (cur != null) {
            if(cur.key.equals(key)) {
                return cur.val;
            }
            cur = cur.next;
        }
        return null;
    }
}

TreeMap使用示例:

import java.util.TreeMap;
import java.util.Map;
public static void TestMap(){
    Map<String, String> m = new TreeMap<>();
// put(key, value):插入key-value的键值对
// 如果key不存在,会将key-value的键值对插入到map中,返回null
    m.put("林冲", "豹子头");
    m.put("鲁智深", "花和尚");
    m.put("武松", "行者");
    m.put("宋江", "及时雨");
    String str = m.put("李逵", "黑旋风");
    System.out.println(m.size());
    System.out.println(m);
// put(key,value): 注意key不能为空,但是value可以为空
// key如果为空,会抛出空指针异常
//m.put(null, "花名");
    str = m.put("无名", null);
    System.out.println(m.size());
// put(key, value):
// 如果key存在,会使用value替换原来key所对应的value,返回旧value
    str = m.put("李逵", "铁牛");
// get(key): 返回key所对应的value
// 如果key存在,返回key所对应的value
// 如果key不存在,返回null
    System.out.println(m.get("鲁智深"));
    System.out.println(m.get("史进"));
//GetOrDefault(): 如果key存在,返回与key所对应的value,如果key不存在,返回一个默认值
    System.out.println(m.getOrDefault("李逵", "铁牛"));
    System.out.println(m.getOrDefault("史进", "九纹龙"));
    System.out.println(m.size());
//containKey(key):检测key是否包含在Map中,时间复杂度:O(logN)
// 按照红黑树的性质来进行查找
// 找到返回true,否则返回false
    System.out.println(m.containsKey("林冲"));
    System.out.println(m.containsKey("史进"));
// containValue(value): 检测value是否包含在Map中,时间复杂度: O(N)
// 找到返回true,否则返回false
    System.out.println(m.containsValue("豹子头"));
    System.out.println(m.containsValue("九纹龙"));
// 打印所有的key
// keySet是将map中的key防止在Set中返回的
    for(String s : m.keySet()){
        System.out.print(s + " ");
    }
    System.out.println();
// 打印所有的value
// values()是将map中的value放在collect的一个集合中返回的
    for(String s : m.values()){
        System.out.print(s + " ");
    }
    System.out.println();
// 打印所有的键值对
// entrySet(): 将Map中的键值对放在Set中返回了
    for(Map.Entry<String, String> entry : m.entrySet()){
        System.out.println(entry.getKey() + "--->" + entry.getValue());
    }
    System.out.println();
}

 


二、Set

Set与Map主要的不同有两点:Set是继承自Collection的接口类,Set中只存储了Key。
 
常见方法说明
36806fd5bfea4a3682513e02124fbb43.png
 
注意:
1. Set是继承自Collection的一个接口类
2. Set中只存储了key,并且要求key一定要唯一
3. TreeSet的底层是使用Map来实现的,其使用key与Object的一个默认对象作为键值对插入到Map中的
4. Set最大的功能就是对集合中的元素进行去重
5. 实现Set接口的常用类有TreeSet和HashSet,还有一个LinkedHashSet,LinkedHashSet是在HashSet的基础上维护了一个双向链表来记录元素的插入次序。
6. Set中的Key不能修改,如果要修改,先将原来的删除掉,然后再重新插入
7. TreeSet中不能插入null的key,HashSet可以。
 
7c56d054196046e2b5c58f840606d75b.png
 
TreeSet使用示例:

import java.util.TreeSet;
import java.util.Iterator;
import java.util.Set;
public static void TestSet(){
    Set<String> s = new TreeSet<>();
    // add(key): 如果key不存在,则插入,返回ture
    // 如果key存在,返回false
    boolean isIn = s.add("apple");
    s.add("orange");
    s.add("peach");
    s.add("banana");
    System.out.println(s.size());
    System.out.println(s);
    isIn = s.add("apple");
    // add(key): key如果是空,抛出空指针异常
    //s.add(null);
    // contains(key): 如果key存在,返回true,否则返回false
    System.out.println(s.contains("apple"));
    System.out.println(s.contains("watermelen"));
    // remove(key): key存在,删除成功返回true
    // key不存在,删除失败返回false
    // key为空,抛出空指针异常
    s.remove("apple");
    System.out.println(s);
    s.remove("watermelen");
    System.out.println(s);
    Iterator<String> it = s.iterator();
    while(it.hasNext()){
        System.out.print(it.next() + " ");
    }
    System.out.println();
}

 

总结

    Map与Set这两个接口由于出色的查找效率,为之后的一些算法题中在优化时间上发挥着重要的作用,不过由于创建需要开辟大量空间,是典型的空间换时间,在实际应用中应该根据需要选用。还是哪句话,没有最好的数据结构,只有最适合的数据结构。


那么本篇文章就到此为止了,如果觉得这篇文章对你有帮助的话,可以点一下关注和点赞来支持作者哦。作者还是一个萌新,如果有什么讲的不对的地方欢迎在评论区指出,希望能够和你们一起进步✊

08403404d82e4ca19e76b10b45ca5f28.png

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CTFHUB | web进阶 | PHP | Bypass disable_function | Backtrace UAF

开启题目 查看源码&#xff0c;发现可以蚁剑连接 进入之后无发现&#xff0c;使用插件 PHP7 Backtrace UAF 之后直接进入终端了 查看根目录之后发现了有两个 flag 文件&#xff0c;之后发现了本题的 flag

[SWPU2019]Web11

打开题目&#xff0c;看到登录口&#xff0c;注册账号看看 admin2&#xff0c;112 申请发布一下广告&#xff0c;sql注入试试 查看详情 看到sql&#xff0c;猜测sql注入&#xff0c;进行测试时发现空格、or、#、--、and等进行了过滤&#xff0c;目前基本可以确定注入点在这个地…

缺人!需求暴涨超300%!年薪超50万元!这一风口,带来大机遇

目前&#xff0c;秋季招聘快来了&#xff0c;随着人工智能应用的爆发&#xff0c;生成式人工智能的招聘市场也十分火爆。 在一家大型人工智能软件公司&#xff0c;团队负责人告诉记者&#xff0c;团队主要做基于大模型的办公协作类软件的开发&#xff0c;近期正在升级一款面向…

macOS Ventura 13.6.9 (22G830) Boot ISO 原版可引导镜像下载

macOS Ventura 13.6.9 (22G830) Boot ISO 原版可引导镜像下载 2024 年 8 月 8 日凌晨&#xff0c;macOS Sonoma 14.6.1 发布&#xff0c;本更新包含了重要的错误修复&#xff0c;并解决了导致高级数据保护无法启用或停用的问题。同时带来了 macOS Ventura 13.6.9 安全更新。 …

LVS(Linux virual server)详解

目录 一、LVS&#xff08;Linux virual server&#xff09;是什么&#xff1f; 二、集群和分布式简介 2.1、集群Cluster 2.2、分布式 2.3、集群和分布式 三、LVS运行原理 3.1、LVS基本概念 3.2、LVS集群的类型 3.2.1 nat模式 3.2.2 DR模式 3.2.3、LVS工作模式总结 …

IntelliJ IDEA 2024.2 发布:Spring Data JPA即时查询、自动补全cron表达式

今早看到&#xff0c;IntelliJ IDEA 2024.2 发布的邮件提示&#xff0c;看了一眼这个版本更新的新特性真的太适合我了&#xff01;也许这些能力对关注DD的小伙伴也有帮助&#xff0c;所以搞篇博客介绍和推荐一下。下面就来一起看看这个版本中推出的几个强大新特性。 Spring Da…

解密 Coretime:Polkadot 区块链资源分配的新革命

作者&#xff1a;PaperMoon Kaichao 高峰期打车&#xff0c;小编往往需要承受溢价车费&#xff0c;甚至还要不停加上小费&#xff0c;才可能在“前方排队 300人”的恐怖等待中获得优先打车的机会。但实际上&#xff0c;只要走出了拥挤路段&#xff0c;即使是高峰期&#xff0c…

Python装饰器之@property使用详解

概要 在Python中&#xff0c;property装饰器是一种强大且优雅的工具&#xff0c;用于定义属性方法&#xff0c;使得类的属性访问更加直观和安全。property装饰器可以让方法像属性一样被访问&#xff0c;从而在不改变接口的情况下对类的属性访问进行控制。本文将详细介绍proper…

VMware虚拟机和Docker的备份与恢复

目录 1. VMware虚拟机的快照备份 1.1 VMware本机的快照备份 1.2 VMware快照备份到另一电脑 2. Docker知识点 2.1 Docker镜像和容器的关系 2.2 Docker的存储卷 2.3 Docker命令简介 2.4 删除Anylink镜像 3. Docker备份和恢复 3.1 确定要回滚的容器和版本 3.2 备份当前…

UE开发中的设计模式(二) —— 中介者模式

上一篇文章介绍了观察者模式如何降低观察者和目标之间的耦合&#xff0c;并通过一个实例具体实现了观察者模式&#xff0c;本篇文章从上篇文章的实例继续&#xff0c;介绍中介者模式是如何带来对象间进一步的松耦合。 文章目录 问题提出概述问题解决总结优点缺点模式应用 参考资…

Powershell 禁用系统更新

创建一个关闭系统更新脚本 脚本系统兼容10,11,2012,206,2019,2022,2025powershell-install-stop-System-update.ps1 <# Powershell Install stop System update +++++++++++++++++++++++++++++++++++++++++++++++++++++ + _____ _____ _ …

【竞技宝】奥运会:法国国奥VS西班牙国奥

北京时间8月10日法国国奥在巴黎奥运会男足决赛中跟西班牙国奥狭路相逢&#xff0c;这场比赛对于主帅亨利来说&#xff0c;有着极为特殊的意义。因为&#xff0c;亨利将带领法国国奥队冲击他执教生涯首枚奥运会金牌。法国足协邀请亨利出任国奥队主帅&#xff0c;就是希望他能带领…

Mac 连接 Synology NAS【Finder】

对于 Mac 用户&#xff0c;建议使用 Finder 或 Cyberduck 通过WebDAV连接到Synology NAS 在上一篇文章中介绍了如何使用【Cyberduck 】连接到Synology NAS 这一篇文章介绍【Finder】连接到Synology NAS 相关文章&#xff1a; 注重任如何使用 Synology NAS 的套件或其他软件…

纸质文物的数字化革命:RFID技术的应用与影响

在这个数字化的时代&#xff0c;我们见证了技术的革新如何将历史重新点燃。纸质文物&#xff0c;这些人类文明的宝贵篇章&#xff0c;正经历一场由RFID技术引领的革命。 数字化浪潮不仅改变了我们的生活&#xff0c;也重塑了我们保护和传承历史的方式。纸质文物的数字化管理&am…

代码随想录训练营 Day24打卡 回溯算法part03 93. 复原IP地址 78. 子集 90. 子集II

代码随想录训练营 Day24打卡 回溯算法part03 一、 力扣93. 复原IP地址 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 ‘.’ 分隔。 例如&#xff1a;“0.1.2.201” 和 “192.168.1…

扩展【从0制作自己的ros导航小车】C++_ROS_QT5联合编译,简单界面为ROS开发增添交互

从0制作自己的ros导航小车 前言一、环境搭建二、联合编译三、测试 前言 前面已经实现了导航功能&#xff0c;对于之后的一些开发&#xff0c;有交互能力是比较重要的&#xff0c;比如小车上连接一块屏幕&#xff0c;通过屏幕来选择模式&#xff0c;可视化等等。QT是不错的选择…

2024年云计算企业CRM应用与选型研究报告

数字化时代&#xff0c;所有行业都在经历着数字化转型带来的效率革命。在业务流程、协同办公、数据收集和利用、决策方式等诸多方面&#xff0c;在数字化转型的加持下&#xff0c;各行各业的企业都会经历从低效到高效、从无序杂乱到标准化流程和数据驱动决策的成长蜕变。 在IC…

LeetCode 100道题目和答案(一)

1.两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以按…

【安卓】SQLite数据库存储-创建数据库与增删改查

文章目录 创建数据库更新数据库增加数据修改数据删除数据查询数据 安卓专门提供了一个SQLiteOpenHelper帮助类&#xff0c;借助这个类可以非常简单地对数据库进行创建和升级。SQLiteOpenHelper是一个抽象类&#xff0c;使用它需要创建一个自己的帮助类去继承它。SQLiteOpenHelp…

巴黎同款,六自由度技术还原赛场决定性瞬间!

现代纪实摄影大师亨利布列松&#xff0c;曾提出了“决定性瞬间”&#xff08;The Decisive Moment&#xff09;理论——拍摄者捕捉到的画面越稍纵即逝&#xff0c;越难以复制&#xff0c;越宝贵。 很多摄影师的经典作品&#xff0c;都来自那决定性的千分之一秒。 ● 布列松摄于…