【数据结构】mapset详解

news2024/9/28 11:24:38

在这里插入图片描述

🍁1. Set系列集合

Set接口是一种不包含重复元素的集合。它继承自Collection接口,所以可以使用Collection所拥有的方法,Set接口的实现类主要有HashSetLinkedHashSetTreeSet等,它们各自以不同的方式存储元素,但都遵循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>() {
            @Override
            public 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;
    }


    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public 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>() {
            @Override
            public 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>() {
            @Override
            public 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<>();
        //统计单词个数并存入map
        for (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>>() {
            @Override
            public 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存入ArrayList
        for (int i = 0; i < k; i++) {
            ans.add(minHeap.poll().getKey());
        }
        //题目要求出现频率由高到低,进行翻转
        Collections.reverse(ans);
        return ans;
    }

在这里插入图片描述

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

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

相关文章

Linux常用得操作命令

1.查看ip地址------ifconfig 2.在终端中输入该命令&#xff0c;可以查看当前所在位置------pwd 3.man和–help man命令 1.man命令可以查看某个命令得具体用法 2.man命令怎么翻页 空格 3.man命令按q退出 help命令------help&#xff0c;也可以查看一个命令的帮助&#xff0c…

JavaWeb基础2:XML/Tomcat/Servlet

JavaWeb基础2&#xff1a;XML/Tomcat/Servlet (qq.com)

vim编辑器的使用【vim常用指令介绍】

1.1 vim 简介 vim 编辑器最初是 vi 编辑器&#xff0c;vi 编辑器是 Unix 系统最初的编辑器。允许查看文件内容和在文件中移动、插入、编辑和替换文本。后来开发人员对它做了一些改进。并重命名为 vim。 1.2 学习 vim 的理由 因为几乎任何一个发行版都有 vi/vim 编辑器&#xf…

从手动到自动:WMS系统带来的仓储革命

仓库管理系统&#xff08;WMS&#xff0c;Warehouse Management System&#xff09;在仓储业的发展中扮演了至关重要的角色。它的演变从手动管理到自动化管理&#xff0c;不仅大提升了仓储效率&#xff0c;还改变了企业的运营模式。 一、手动管理阶段 在WMS系统普及之前&#…

nginx负载均衡及软件平滑升级!!!

一、负载均衡 早期的网站流量和业务功能都比较简单&#xff0c;单台服务器足以满足基本的需求&#xff0c;但是随着互联网的发展&#xff0c;业务流量越来越大并且业务逻辑也跟着越来越复杂&#xff0c;单台服务器的性能及单点故障问题就凸显出来了&#xff0c;因此需要多台服…

【Visual Studio Code】源代码管理 传入/传出 更改配置开关

July 2024 (version 1.92)版本更新的Visual Studio Code 增加了 【源代码管理 - 传入/传出】的可视化视图。 但是目前发现也会导致加载变慢 占用页面的影响&#xff0c;如果希望关闭该视图&#xff0c; 可以在设置里搜索 scm.showHistoryGraph 关闭即可

计网:从输入URL到网页显示期间发生了什么

1、URL包含的信息 我们输入的url中包含着一些信息&#xff1a; http&#xff1a;表示的此次我们使用的什么协议/www.baidu.com&#xff1a;表示的是我们想要访问的服务器名称&#xff0c;也就是域名dir3/home.html&#xff1a;表示我们所要访问的资源 2、通过DNS解析URL获得I…

JAVA中的JMM(Java 内存模型)详解

1.JMM概念 Java 内存模型&#xff08;Java Memory Model 简称JMM&#xff09;是一种抽象的概念&#xff0c;并不真实存在&#xff0c;指一组规则或规范&#xff0c;通过这组规范定义了程序中各个变量的访问方式。 因为在不同的硬件生产商和不同的操作系统下&#xff0c;内存的访…

嵌入式安全:Provencore Secure os

嵌入式安全有何独特之处? 嵌入式安全领域的领导者 ProvenRun 宣布,其旗舰产品 ProvenCore for ARM™ Cortex-A 最近获得了 通用标准 (CC) EAL7 认证。这是全球首创,因为没有其他操作系统或可信执行环境 (TEE) 达到该安全级别。相比之下,移动安全市场上第二安全的 TEE(对于…

版本控制案例:全球虚拟制片领导者Dimension借助Perforce Helix Core管理大型二进制文件,实现跨地域团队协作,简化制作流程(上)

创建虚拟世界和人类角色需要一系列的软件工具。但最终愿景很少是由单一工作室独立完成的。对于大型项目&#xff0c;工作室需要通力合作&#xff0c;将全球的团队成员和数字资产联合起来。 Dimension Studio——体积内容捕捉和虚拟制片领域的领导者——不断将新技术和新方法融…

传统产品经理 vs AI产品经理

随着科技的日新月异和技术的不断革新&#xff0c;AI技术如今已深度融入各行各业&#xff0c;使得身处此领域的产品经理们迎来了前所未有的新挑战与广阔机遇。以下是我精心整理的内容&#xff0c;旨在分享传统产品经理如何顺应时代洪流&#xff0c;成功转型为AI产品经理的策略与…

Java面试之操作系统

1、冯诺依曼模型 运算器、控制器、存储器、输入设备、输出设备 32位和64位CPU最主要区别是一次性能计算多少字节数据&#xff0c;如果计算的数额不超过 32 位数字的情况下&#xff0c;32 位和 64 位 CPU 之间没什么区别的&#xff0c;只有当计算超过 32 位数字的情况下&#…

中国篆刻孙溟㠭凿木《应无所住而生其心》

应无所住而生其心 弘一法师言&#xff1a;学佛不是让你出家&#xff0c;也不是让你变得与众不同。学佛就是一个正常生活的人&#xff0c;一个善良的人懂得用佛法降服自心&#xff0c;消除烦恼所有有皆是虚妄&#xff0c;若见诸相非相&#xff0c;即见真我。 孙溟㠭凿木《应无…

Vue3发送验证码,开启倒计时,并且倒计时结束前无法点击

目录 1.最终效果 2.HTML 3.JS 1.最终效果 先看效果&#xff0c;点击发送验证码&#xff0c;然后开启倒计时&#xff0c;倒计时结束前无法再次发送&#xff0c;并且该按钮处于无法选中状态 废话少说&#xff0c;上干货&#xff0c;直接看代码 2.HTML 按钮部分内容&#xf…

揭秘eBay店铺排名提升秘诀:测评自养号的好处

在竞争激烈的电商市场&#xff0c;eBay作为全球知名的在线拍卖及购物网站&#xff0c;为卖家提供了广阔的舞台。如何在众多商品中脱颖而出&#xff0c;提升产品排名&#xff0c;成为每位eBay卖家关注的焦点。 eBay卖家如何提升排名&#xff1f; 1、关键词优化&#xff1a;关键…

适合制造业的项目管理软件都有哪些?

项目管理软件涉及进度、预算成本、资源、开发、流程、质量、风险、工时、知识文档、商务等各个方面&#xff0c;是企业项目管理领域的重要辅助工具&#xff0c;能够帮助组织提高项目管理水平与质量&#xff0c;确保项目顺利进行。 一、 奥博思 PowerProject 项目管理系统 Pow…

汇川Autoshop编程软件连接PLC并下载程序的具体步骤示例

汇川Autoshop编程软件连接PLC并下载程序的具体步骤示例 如下图所示,打开AutoShop编程软件后,新建项目,点击工具—通讯设置, 如下图所示,在弹出的窗口中选择通讯类型(这里选择以太网),设置好IP地址,然后点击搜索,正常情况下可以搜到PLC, 如下图所示,如果搜索不到PLC…

我在高职教STM32——I2C通信入门(1)

大家好,我是老耿,高职青椒一枚,一直从事单片机、嵌入式、物联网等课程的教学。对于高职的学生层次,同行应该都懂的,老师在课堂上教学几乎是没什么成就感的。正是如此,才有了借助CSDN平台寻求认同感和成就感的想法。在这里,我准备陆续把自己花了很多心思设计的教学课件分…

基于PREEvision的架构方案评估

Introduction 随着汽车行业的快速发展和消费者需求的日益复杂化&#xff0c;现代汽车已不再仅仅是机械设备的集合体&#xff0c;更是高度复杂的电子和电气系统的结合体。在这样的背景下&#xff0c;如何有效地设计和优化汽车电气架构&#xff0c;成为制造商和供应商面临的关键…

CSS实现元素hover时背景色拉伸渐变

HTML代码 <ul><li><p><a href"#">Facebook搜索</a></p></li><li><p><a href"#">Instagram搜索</a></p></li><li><p><a href"#">Google搜索&…