Map和Set

简介: Map和Set

前提:Map和Set的底层是一棵红黑树,红黑树的本质是一颗二叉搜索树.

概念及场景

Map和set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关。

1.直接遍历,时间复杂度为O(N),元素如果比较多效率会非常慢

2.二分查找,时间复杂度为O(log2N) ,但搜索前必须要求序列是有序的


上述排序比较适合静态类型的查找,即一般不会对区间进行插入和删除操作了,而现实中的查找比如:


1.根据姓名查询考试成绩

2.通讯录,即根据姓名查询联系方式

3.不重复集合,即需要先搜索关键字是否已经在集合中

可能在查找时进行一些插入和删除的操作,即动态查找,那上述两种方式就不太适合了,本节介绍的Map和Set是一种适合动态查找的集合容器。


模型

一般把搜索的数据称为关键字(Key),和关键字对应的称为值(Value),将其称之为Key-value的键值对,所以模型会有两种:

1.纯 key 模型,比如:

有一个英文词典,快速查找一个单词是否在词典中快速查找某个名字在不在通讯录中

2.Key-Value 模型,比如:

统计文件中每个单词出现的次数,统计结果是每个单词都有与其对应的次数:<单词,单词出现的次数> 梁山好汉的江湖绰号:每个好汉都有自己的江湖绰号

而Map中存储的就是key-value的键值对,Set中只存储了Key。


Map的使用

关于Map的说明

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


关于Map.Entry

Map.Entry 是Map内部实现的用来存放键值对映射关系的内部类,该内部类中主要提供了

的获取,value的设置以及Key的比较方式。

2.png

注意:Map.Entry并没有提供设置Key的方法


Map的常用方法说明

2.png

注意:

1.Map是一个接口,不能直接实例化对象,如果要实例化对象只能实例化其实现类TreeMap或者HashMap

2.Map中存放键值对的Key是唯一的,value是可以重复的

3.在Map中插入键值对时,key可以为空,value也可以为空,也可以不为空.

4.Map中的Key可以全部分离出来,存储到Set中来进行访问(因为Key不能重复)。

5.Map中的value可以全部分离出来,存储在Collection的任何一个子集合中(value可能有重复)。

6.Map中键值对的Key不能直接修改,value可以修改,如果要修改key,只能先将该key删除掉,然后再来进行重新插入。

7.TreeMap和HashMap的区别

2.png


代码示例

public class MapDemo {
    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
        //put的书写顺序不能决定打印的顺序
        //put是根据一个函数存放的,叫做哈希函数
        map.put("2", 4);
        map.put("3", 5);
        map.put("4", 6);
        //输出结果为{2=4, 3=5, 4=6}
        System.out.println(map);
        Map<String, Object> map1 = new HashMap<>();
        map1.put("sb", 2);
        map1.put("sb", 3);
        //如果key存在,会使用value替换原来key所对应的value,返回新value
        //结果为{sb=3}
        System.out.println(map1);
        Map<String, Object> map2 = new HashMap<>();
        map2.put("sb", 4);
        // get(key): 返回key所对应的value
        // 如果key存在,返回key所对应的value
        // 如果key不存在,返回null
        // 结果为4
        System.out.println(map2.get("sb"));
        Map<String, Object> map3 = new HashMap<>();
        //如果key不存在,返回一个默认值
        int a = (int) map3.getOrDefault("sb", 9);
        //结果为9
        System.out.println(a);
        Map<String, Object> map4 = new HashMap<>();
        map4.put("2", 4);
        map4.put("3", 5);
        map4.put("4", 6);
        //set集合不能存放相同元素,keySet方法只获取key值,返回所有 key 的不重复集合
        Set<String> set = map4.keySet();
        //结果为[2, 3, 4]
        System.out.println(set);
        Map<String, Integer> map5 = new HashMap<>();
        map5.put("2", 4);
        map5.put("3", 5);
        map5.put("4", 6);
        //entrySet是为了返回所有的 key-value 映射关系
        Set<Map.Entry<String, Integer>> set1 = map5.entrySet();
        /*
        输出结果为
        4 2
        5 3
        6 4
         */
         // 打印所有的键值对
        for (Map.Entry<String, Integer> entry : set1) {
            System.out.println(entry.getValue() + " " +
                    entry.getKey());
        }
        Map<String, Integer> map6 = new HashMap<>();
        map6.put("2", 4);
        map6.put("3", 5);
        map6.put("4", 6);
        //检测key是否包含在Map中,时间复杂度:O(logN)
        // 按照红黑树的性质来进行查找
        // 找到返回true,否则返回false
        boolean b = map6.containsKey("2");
        //结果为true
        System.out.println(b);
        Map<String, Integer> map7 = new HashMap<>();
        map7.put("2", 4);
        map7.put("3", 5);
        map7.put("4", 6);
        // containValue(value): 检测value是否包含在Map中,时间复杂度: O(N)
        // 因为TreeMap是按照Key进行组织的,因此查找value时候就需要整体遍历
        // 找到返回true,否则返回false
        boolean c = map6.containsValue(4);
        //结果为true
        System.out.println(c);
    }
}

Set的说明

Set与Map主要的不同有两点:Set是继承自Collection的接口类,Set中只存储了Key,并且Set中不能存储相同的元素。所以我们经常会使用Set来进行去重.


常见方法说明

2.png

注意:

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

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

3.Set的底层是使用Map来实现的,其使用key与Object的一个默认对象作为键值对插入到Map中的

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

5.实现Set接口的常用类有TreeSet和HashSet,还有一个LinkedHashSet,LinkedHashSet是在HashSet的基础 上维护了一个双向链表来记录元素的插入次序。

6.Set中的Key不能修改,如果要修改,先将原来的删除掉,然后再重新插入

7.TreeSet和HashSet的区别

注意:时间复杂度为O(1)是因为Set的底层是Map,而HashSet的底层是HashMap,HashMap的时间复杂度为O(1).则HashSet的时间复杂度为O(1)

2.png

8.set的add方法中,当数字的范围大于65535后,数字的有序性就不能保证了,也就是说set中的add方法其实插入小于65535的数字的时候是有序的,在插入大于65535的数字后就变成无序数字了.并且需要注意的是,Set集合中所有插入的数字都是非重复的,即Set集合中不可能存储重复的数字.


代码示例

在这里我就说下Set中的元素转为数组返回的问题,也就是toArray方法:注意这里不能使用强转,写法按照下面代码的写法才可以发生转化.

public class MapDemo1 {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(4);
        set.add(5);
        Integer[] a= set.toArray(new Integer[5]);
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i]+" ");
        }
    }
}


面试题目

题目一

2.png

1的代码:

public static int findFirstReapeatNumber() {
        Random random = new Random();
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10_0000; i++) {
            list.add(random.nextInt(1_0000));
        }
        HashSet<Integer> set = new HashSet<>();
        for (int i = 0; i < list.size(); i++) {
            if (!set.contains(list.get(i))) {
                set.add(list.get(i));
            } else {
                return list.get(i);
            }
        }
        return -1;
    }

2的代码:

因为要把十万个数据中的元素全部去重,就需要使用到Set集合,它就是自动去重的.


public static Set<Integer> deputil() {
        Random random = new Random();
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10_0000; i++) {
            list.add(random.nextInt(1_0000));
        }
        HashSet<Integer> set = new HashSet<>();
        for (int i = 0; i < list.size(); i++) {
            set.add(list.get(i));
        }
        return set;
    }

3的代码:

public class MapDemo1 {
    public static void func() {
        Random random = new Random();
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add(random.nextInt(10));
        }
        System.out.println(list);
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < list.size(); i++) {
            Integer key = list.get(i);
            if (map.get(key) == null) {
                map.put(key, 1);
            } else {
                Integer value = map.get(key);
                map.put(key, value + 1);
            }
        }
        for (Map.Entry<Integer, Integer> map1 : map.entrySet()) {
            if (map1.getValue() > 1) {
                System.out.println(map1.getKey() + "=" + map1.getValue());
            }
        }
    }
    public static void main(String[] args) {
        func();
    }
}

题目二

只出现一次的数字


题目三

复制带随机指针的链表


题目四

宝石与石头


题目五

旧键盘


题目六

前K个高频单词


相关文章
|
7天前
|
算法
你对Collection中Set、List、Map理解?
你对Collection中Set、List、Map理解?
40 18
你对Collection中Set、List、Map理解?
|
17天前
|
存储 C++ 容器
【C++】map、set基本用法
本文介绍了C++ STL中的`map`和`set`两种关联容器。`map`用于存储键值对,每个键唯一;而`set`存储唯一元素,不包含值。两者均基于红黑树实现,支持高效的查找、插入和删除操作。文中详细列举了它们的构造方法、迭代器、容量检查、元素修改等常用接口,并简要对比了`map`与`set`的主要差异。此外,还介绍了允许重复元素的`multiset`和`multimap`。
25 3
【C++】map、set基本用法
|
17天前
|
存储 算法 C++
【C++】unordered_map(set)
C++中的`unordered`容器(如`std::unordered_set`、`std::unordered_map`)基于哈希表实现,提供高效的查找、插入和删除操作。哈希表通过哈希函数将元素映射到特定的“桶”中,每个桶可存储一个或多个元素,以处理哈希冲突。主要组成部分包括哈希表、哈希函数、冲突处理机制、负载因子和再散列,以及迭代器。哈希函数用于计算元素的哈希值,冲突通过开链法解决,负载因子控制哈希表的扩展。迭代器支持遍历容器中的元素。`unordered_map`和`unordered_set`的插入、查找和删除操作在理想情况下时间复杂度为O(1),但在冲突较多时可能退化为O(n)。
15 5
|
2月前
|
存储 JavaScript 前端开发
Set、Map、WeakSet 和 WeakMap 的区别
在 JavaScript 中,Set 和 Map 用于存储唯一值和键值对,支持多种操作方法,如添加、删除和检查元素。WeakSet 和 WeakMap 则存储弱引用的对象,有助于防止内存泄漏,适合特定场景使用。
|
3月前
|
存储 Java API
【数据结构】map&set详解
本文详细介绍了Java集合框架中的Set系列和Map系列集合。Set系列包括HashSet(哈希表实现,无序且元素唯一)、LinkedHashSet(保持插入顺序的HashSet)、TreeSet(红黑树实现,自动排序)。Map系列为双列集合,键值一一对应,键不可重复,值可重复。文章还介绍了HashMap、LinkedHashMap、TreeMap的具体实现与应用场景,并提供了面试题示例,如随机链表复制、宝石与石头、前K个高频单词等问题的解决方案。
42 6
【数据结构】map&set详解
|
2月前
|
存储 缓存 Java
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
41 1
|
3月前
|
算法
你对Collection中Set、List、Map理解?
你对Collection中Set、List、Map理解?
39 5
|
3月前
|
存储 JavaScript 前端开发
js的map和set |21
js的map和set |21
|
3月前
|
存储 前端开发 API
ES6的Set和Map你都知道吗?一文了解集合和字典在前端中的应用
该文章详细介绍了ES6中Set和Map数据结构的特性和使用方法,并探讨了它们在前端开发中的具体应用,包括如何利用这些数据结构来解决常见的编程问题。
ES6的Set和Map你都知道吗?一文了解集合和字典在前端中的应用
|
4月前
|
存储 安全 Java
java集合框架复习----(4)Map、List、set
这篇文章是Java集合框架的复习总结,重点介绍了Map集合的特点和HashMap的使用,以及Collections工具类的使用示例,同时回顾了List、Set和Map集合的概念和特点,以及Collection工具类的作用。
java集合框架复习----(4)Map、List、set