0
点赞
收藏
分享

微信扫一扫

Map和Set

吃面多放酱 2022-01-23 阅读 147

目录


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

概念及场景

Map和set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关。
1.直接遍历,时间复杂度为O(N),元素如果比较多效率会非常慢
2.二分查找,时间复杂度为O(log2N) ,但搜索前必须要求序列是有序的

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

1.根据姓名查询考试成绩
2.通讯录,即根据姓名查询联系方式
3.不重复集合,即需要先搜索关键字是否已经在集合中
可能在查找时进行一些插入和删除的操作,即动态查找,那上述两种方式就不太适合了,本节介绍的MapSet是一种适合动态查找的集合容器。

模型

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

Map的使用

关于Map的说明

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

关于Map.Entry

Map.Entry<K, V> 是Map内部实现的用来存放<key, value>键值对映射关系的内部类,该内部类中主要提供了
<key, value>的获取,value的设置以及Key的比较方式。
在这里插入图片描述
注意:Map.Entry<K,V>并没有提供设置Key的方法

Map的常用方法说明

在这里插入图片描述
注意:
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的区别
在这里插入图片描述

代码示例

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来进行去重.

常见方法说明

在这里插入图片描述
注意:
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)
在这里插入图片描述
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]+" ");
        }
    }
}

面试题目

题目一

在这里插入图片描述
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个高频单词

举报

相关推荐

0 条评论