Map和Set详细介绍~

Map 和S et 是 一种专门 用来进行搜索的 数据结构。 适合动态查找

一、Map(存储key-value) 

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

Map和Set详细介绍~_第1张图片

常用的方法:

1、map.put(K的类型 key, V的类型 value)   往里放元素

        Map map=new HashMap<>();
        map.put("abc",3);//put是往里放元素      
        map.put("bit",2);
        map.put("hello",4);
        System.out.println(map);//会自动调用toString方法

 

注意:hashmap存储元素的时候,不是按照存储的顺序进行打印的

          存储的时候,是根据哈希函数来进行存储的。

        Map map = new HashMap<>();
        map.put("abc", 3);
        map.put("bit", 2);
        map.put("bit", 4);
        System.out.println(map);

注意: 存储元素时,如果key相同,value值会被覆盖

2、V的类型   =map.get(key)   通过key值获取value值

int ret=map.get("abc");//ret为3

3、V的类型   =map.getOrDefault(key,没有key所对值时要返回的值)

map.getOrDefault("bit2",98);//找不到bit2,也就找不到对应的value,此时就返回设定的value值98

4、V的类型   =map.remove(key)  删除 

Integer ret2=map.remove("bit");//删除值为bit的
System.out.println(ret2);//2

5、Set set=map.keySet()    返回所有 key 不重复集合

      因为Set这个集合当中存储的元素都是不重复的

Map map = new HashMap<>();
map.put("abc", 3);//put是往里放元素4
map.put("bit", 2);
map.put("hello", 4);
Set set=map.keySet();//此时就把所有key=放在了set里
System.out.println(set);//abc bit hello

 6、Collection   =map. values()     返回所有 value 的可重复集合

7、Set>   =map.entrySet()    返回所有的 key-value 映射关系
Map和Set详细介绍~_第2张图片
        Map map = new HashMap<>();
        map.put("abc", 3);
        map.put("bit", 2);
        map.put("bit", 4);
        map.put(null,null);//用HashMap可以放null,但是用TreeMap不可以放null
        System.out.println(map);
        Set> entrySet=map.entrySet();//也就是在Set里,每个元素的类型是Map.Entry
        for (Map.Entry entry:entrySet) {//遍历Set
            System.out.println(entry.getKey()+"->"+entry.getValue());
        }

8、boolean   =map.containsKey(Object key)     判断是否包含 key

9、boolean   =map.containsValue(Object value)   判断是否包含value

注意:

1. Map是一个接口,不能直接实例化对象,如果要实例化对象只能实例化其实现类TreeMap或者HashMap
2. Map中存放键值对的Key是唯一的value是可以重复的
3.对于HashMap来说,在Map中插入键值对时,key可以为空
   对于TreeMap来说,Map中插入键值对时,key不能为空,否则就会抛NullPointerException异常,但是value可以为空
4. Map中的Key可以全部分离出来(keySet方法),存储到Set来进行访问(因为Key不能重复)
5. Map中的value可以全部分离出来(values方法),存储在Collection的任何一个子集合中(value可能有重复)
  6. Map中键值对的Key不能直接修改,value可以修改,如果要修改key,只能先将该key删除掉,然后再来进行 重新插入。
7. TreeMapHashMap的区别

 Map和Set详细介绍~_第3张图片


 二、Set(存储key)会自动去重

Map和Set详细介绍~_第4张图片

 常见方法:

1、set.add(E e)        添加元素,但重复元素不会被添加成功

        Set set=new HashSet<>();
        set.add(1);//往set里添加元素
        set.add(2);
        set.add(1);
        System.out.println(set);

2、set.clear()         清空集合

3、boolean   =set.contains(Object o)         判断 o 是否在集合中
4、Iterator    =set.iterator()         返回迭代器
        Set set=new HashSet<>();
        set.add(1);//往set里添加元素
        set.add(2);
        set.add(3);
        Iteratoriterator=set.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }

Map和Set详细介绍~_第5张图片

5、boolean    =set.remove(Object o)        删除集合中的 o

6、int   =set.size()         返回set中元素的个数

7、boolean   =set.isEmpty()         检测set是否为空,空返回true,否则返回false
8、Object[]   =set.toArray()         将set中的元素转换为数组返回
9、boolean    =set.containsAll(Collection c)         集合c中的元素是否在set中全部存在,是返回true,否则返回 false
10、boolean   =ret.addAll(Collection c)        将集合c中的元素添加到set中,可以达到去重的效果
注意:
1. Set继承自Collection的一个接口类
2. Set中只存储了key,并且要求key一定要唯一
3.实现Set接口的常用类有TreeSet和HashSet,还有一个LinkedHashSet
4.Set中的Key不能修改,如果要修改,先将原来的删除掉,然后再重新插入
5. Set不能插入null的key
6. Set最大的功能就是对集合中的元素进行去重
7.TreeSetHashSet的区别
Map和Set详细介绍~_第6张图片

 练习题:

1、给定1W个数据,统计每个数据出现的次数(思路:用Map

思路:将每个值都放在map里,每次放的时候检查一下,如果有这个值,则在原来值所对的value值+1,如果没这个值,则把这个值放在map里,value值为1

    public static Map func1(int[]array){//key是关键字 value是出现的次数
        Map map=new HashMap<>();
        //判断array中的元素是否在map中,如果不在就是1,在就是在原来的基础上+1
        for (int x:array) {//取出数组里的每个元素x
            if(map.get(x)==null){//看x在不在map里
                map.put(x,1);
            }else{
                int val=map.get(x);//如果在看看已经出现几次了
                map.put(x,val+1);//再在原来的基础上+1
            }
            return map;
        }
    }
    public static void main(String[] args) {
        int[]array=new int[1_0000];
        Random random=new Random();
        for (int i = 0; i < array.length; i++) {
            array[i]=random.nextInt(1000);//随机生成1000个数据,保证了10000个数据里有重复的
        }
        Map map=func1(array);
        System.out.println(map);
    }

2、将1W个数据中的数据去重(涉及到去重,用Set )

public static Set func2(int[]array){
        HashSet set=new HashSet<>();
        for (int x:array) {//将数组里的每个元素放入Set,就可以达到去重的效果
            set.add(x);
        }
        return set;
    }

3、从1W个数据中,找出第一个重复的数据

思路:每次把元素放到Set里,放之前都检查一下set中是不是已经有了

public static int func3(int[]array){
        HashSet set=new HashSet<>();
        for (int x:array) {
            if(set.contains(x)){//如果set里面包含x则证明x是第一个重复的
                return x;
            }
            set.add(x);
        }
        return -1;
    }

4、题目:只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

Map和Set详细介绍~_第7张图片 

public int singleNumber(int[] nums) {
         HashSetset=new HashSet<>();
        for (int x:nums) {
            if(set.contains(x)){//如果在set里就移出去,最后剩下的就是只出现一次的
                set.remove(x);
            }else{
                set.add(x);
            }
        }
        //此时返回set里只存在的那个值,就是所求
        for (int i = 0; i < nums.length; i++) {
            if(set.contains(nums[i])){
                return nums[i];
            }
        }
        return -1;
    }

5、 复制带随机指针的链表

题意:

Map和Set详细介绍~_第8张图片

  思路:用cur遍历链表,链表不为空就创建一个新的节点,然后利用map存一下老节点和新节点的映射关系,直到cur遍历结束,然后再重新遍历cur,根据cur节点从map中找到与cur相对应的值,这样就可以复制链表的next指向和random指向了

Map和Set详细介绍~_第9张图片

    public Node copyRandomList(Node head) {
        Map map=new HashMap<>();
        Node cur=head;
        while(cur!=null){//第一次遍历
            Node node=new Node(cur.val);
            map.put(cur,node);//在map里存好映射关系
            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;
        }
        return map.get(head);//返回复制后链表的头节点
    }

6、 宝石与石头

给你一个字符串 jewels 代表石头中宝石的类型,另有一个字符串 stones 代表你拥有的石头。 stones 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。

字母区分大小写,因此 "a" 和 "A" 是不同类型的石头。

Map和Set详细介绍~_第10张图片

 思路:把宝石放到Set里,再遍历石头,若有和Set里元素重复的,计数器++

public int numJewelsInStones(String jewels, String stones) {
            HashSet set=new HashSet<>();
            for(Character c:jewels.toCharArray()){//将宝石里的元素都放到Set里
                set.add(c);
            }
            int count=0;
            for(Character c:stones.toCharArray()){//遍历石头里的元素
                if(set.contains(c)){//如果set里有和石头元素相同的,就证明这个石头元素是宝石计数器++
                    count++;
                }

            }
            return count;
    }

7、旧键盘 (20)__牛客网
题目:旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及实际被输入的文字,请你列出肯定坏掉的那些键

Map和Set详细介绍~_第11张图片

 

 Map和Set详细介绍~_第12张图片

思路:把实际输出的放到Set里,然后用i遍历预期输出的,如果i的值不在set里,则证明是坏键,但是这时的坏键可能重复输出了,所以还需要把这些坏键再次放入另一个Set里,如果重复则不放,不重复则放入并打印(如果都放入Set,之后再拿出Set里的值会出现顺序的问题)

import java.util.*;

public class Main{
    
    //strExce:7_This_is_a_test    strActual:_hs_s_a_es
    public static void func(String strExce,String strActual){
         HashSet set=new HashSet<>();
        for (char ch:strActual.toUpperCase().toCharArray()) {//将strActual转换成大写再将里面的值放入set
            set.add(ch);
        }
        HashSet broken=new HashSet<>();//用来去除坏键中的重复键
        for (char ch:strExce.toUpperCase().toCharArray()) {//遍历预期输出的值
            //if(!set.contains(ch)){//如果Set里不包含该值证明该值为坏键(但是此时这些坏键可能有重复的)
               if(!set.contains(ch)&&!broken.contains((ch))){
                System.out.print(ch);//如果坏键的broken里面也没有该值说明是坏键,并且此时也保证了坏键能不重复的输出
                broken.add(ch);
            }
        }
    }
    public static void main(String[]args){
        Scanner in=new Scanner(System.in);
        while(in.hasNextLine()){
            String strExce=in.nextLine();
            String strActual=in.nextLine();
            func(strExce,strActual);
        }
    }
}

8、前K个高频单词

 给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。

返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。

意思是:

Map和Set详细介绍~_第13张图片

 Map和Set详细介绍~_第14张图片

思路:因为返回前 k 个出现次数最多的单词,需要建一个小堆

因为最后是由高到低排序,所以将堆顶弹出后还需逆置

    public List topKFrequent(String[] words,int k){
        HashMap map=new HashMap<>();
        //1、统计每个单词出现的次数
        for (String s:words) {
            if(map.get(s)==null){
                map.put(s,1);
            }else{
                int val=map.get(s);
                map.put(s,val+1);
            }
        }
        //2、建立一个大小为K的小根堆
        PriorityQueue> minHeap=new PriorityQueue<>(k, new Comparator>() {
            @Override
            public int compare(Map.Entry o1, Map.Entry o2) {
                if(o1.getValue().compareTo(o2.getValue())==0){//因为在入堆的时候要调用compare,这个情况是在值相等的情况下,单词建大堆到时候逆置就正好由字典顺序输出了
                    return o2.getKey().compareTo(o1.getKey());
                }
                return o1.getValue()-o2.getValue();//小根堆o1-o2
            }

        });
        //3、遍历Map
        for (Map.Entry entry:map.entrySet()) {
            if(minHeap.size() top=minHeap.peek();
                if(top.getValue().compareTo(entry.getValue())==0){//如果值相同,看单词小 的入堆
                    if(top.getKey().compareTo(entry.getKey())>0){
                        minHeap.poll();
                        minHeap.offer(entry);
                    }
                }else{
                    if(top.getValue().compareTo(entry.getValue())<0){//值大的入堆
                        minHeap.poll();
                        minHeap.offer(entry);
                    }
                }
            }
        }
        List ret=new ArrayList<>();
        for (int i = 0; i < k; i++) {
            Map.Entry top=minHeap.poll();
            ret.add(top.getKey());//最后只留下key值
        }
        Collections.reverse(ret);//最后逆置
        return ret;
    }

你可能感兴趣的:(数据结构,java)