Map和Set

Posted ohana!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Map和Set相关的知识,希望对你有一定的参考价值。

目录

一,搜索

1.概念和场景

2. 模型

二,Map

1.关于Map.Entry的说明

2.Map的常用方法

注意事项:

TreeMap 和 HashMap 的区别:

红黑树介绍:

代码示例:

三,Set

1.Set的概念

2.Set的常用方法

注意事项:

TreeSet和HashSet的区别:

代码示例:


一,搜索

1.概念和场景

  • Map和set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关。以前常见的搜索方式有:
  1. 直接遍历,时间复杂度为O(N),元素如果比较多效率会非常慢
  2. 二分查找,时间复杂度为 ,但搜索前必须要求序列是有序的
  • 上述排序比较适合静态类型的查找,即一般不会对区间进行插入和删除操作了
  • 现实问题中的查找都存在动态查找的可能,因此,Map和Set是一种适合动态查找的集合容器

2. 模型

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

  • 纯 key 模型
  1. 有一个英文词典,快速查找一个单词是否在词典中
  2. 快速查找某个名字在不在通讯录中
  • Key-Value 模型
  1. 统计文件中每个单词出现的次数,统计结果是每个单词都有与其对应的次数:<单词,单词出现的次数>
  2. 同一个名字的使用人数,就是名字重复的人数:<名字,重复的人数>
  • Map中存储的就是key-value的键值对,Set中只存储了Key 

二,Map

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

1.关于Map.Entry<k,v>的说明

  • Map.Entry<K, V> 是Map内部实现的用来存放<key, value>键值对映射关系的内部类,该内部类中主要提供了<key, value>的获取,value的设置以及Key的比较方式

  • Map.Entry<K,V>并没有提供设置Key的方法

2.Map的常用方法

注意事项:

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

TreeMap 和 HashMap 的区别:

Map底层结构TreeMapHashMap
底层结构红黑树哈希桶
插入/删除/查找时间复杂度O()O(1)
是否有序关于Key有序无序
是否线程安全线程不安全线程不安全
插入/删除/查找区别需要进行元素比较通过哈希函数计算哈希地址
比较与覆写key必须能够比较,否则会抛出
ClassCastException异常
自定义类型需要覆写equals和
hashCode方法
应用场景需要Key有序场景下Key是否有序不关心,需要更高的时间性能

红黑树介绍:

  • TreeMap底层是红黑树,红黑树底层是二叉搜索树 + 一系列的条件限制
  • 每个结点都有颜色,要么是红色要么是黑色
  • 最长路径中的结点个数不超过最短路径中结点个数的二倍
  • 根节点必须是黑色
  • 每条路径中的黑色结点数量相等
  • 不能有连着的红色结点
  • “叶子结点”必须为黑色(这个叶子结点指的是所有结点的空节点)

代码示例:

import java.util.*;

public class MyMap 
    public static void main(String[] args) 
        Map<String,Integer> m = new TreeMap<>();

        m.put("张三",1);
        m.put("李四",2);
        m.put("王五",3);

        System.out.println(m.get("张三"));  //获取key的value值
        System.out.println(m.getOrDefault("赵六",0));  //如果key不存在,返回默认值
        System.out.println(m.size());  // 获取m的有效键值对

        m.put("张三",100);   //若key已经存在,新的value会代替之前的value,有效键值对并不会增加
        System.out.println(m.size());
        //m.put(null,10); // key不能为空,但是,value可以为空

        System.out.println(m.get("张三"));  //获取新的value

        if(m.containsKey("张三"))
            System.out.println("张三存在");
        else
            System.out.println("张三不存在");
        


        if(m.containsValue(100))
            System.out.println("100存在");
        else
            System.out.println("100不存在");
        

        Set<String> s = m.keySet();
        for (String s1: s) 
            System.out.print(s1 + " ");
        
        System.out.println();
        Collection<Integer> c = m.values();
        for (Integer c1 : c ) 
            System.out.print(c1 + " ");
        
        System.out.println();
        Set<Map.Entry<String,Integer>> me = m.entrySet();
        for (Map.Entry<String,Integer> me1 : me) 
            System.out.print(me1 + " ");
        
        System.out.println();
    

三,Set

1.Set的概念

  • Set不同于Map的是,Set继承自Collection,Set中只存放了key
  • Set的底层也有两种TreeSet和HashSet

2.Set的常用方法

方法解释
boolean add(E e)添加元素,但重复元素不会被添加成功
void clear()清空集合
boolean contains(Object o)判断 o 是否在集合中
Iterator<E> iterator()返回迭代器
boolean remove(Object o)删除集合中的 o
int size()返回set中元素的个数
boolean isEmpty()检测set是否为空,空返回true,否则返回false
Object[] toArray()将set中的元素转换为数组返回
boolean containsAll(Collection<?> c)集合c中的元素是否在set中全部存在,是返回true,否则返回
false
boolean addAll(Collection<? extends
E> c)
将集合c中的元素添加到set中,可以达到去重的效果

注意事项:

  • Set是继承自Collection的一个接口类
  •  Set中只存储了key,并且要求key一定要唯一
  • Set的底层是使用Map来实现的,其使用key与Object的一个默认对象作为键值对插入到Map中的
  • Set最大的功能就是对集合中的元素进行去重
  • 实现Set接口的常用类有TreeSet和HashSet,还有一个LinkedHashSet,LinkedHashSet是在HashSet的基础上维护了一个双向链表来记录元素的插入次序
  • Set中的Key不能修改,如果要修改,先将原来的删除掉,然后再重新插入
  • Set中不能插入null的key

TreeSet和HashSet的区别:

Set底层结构TreeSetHashSet
底层结构红黑树哈希桶
是否有序关于Key有序不一定有序
线程安全不安全不安全
插入/删除/查找区别按照红黑树的特性来进行插入和删除1. 先计算key哈希地址 2. 然后进行
插入和删除
比较与覆写key必须能够比较,否则会抛出
ClassCastException异常
自定义类型需要覆写equals和
hashCode方法
应用场景需要Key有序场景下Key是否有

代码示例:

import java.util.*;

public class TestSet 
    public static void main(String[] args) 
        Set<String> s = new TreeSet<>();
        // add(key): 如果key不存在,则插入,返回true
        // 如果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("watermelon"));
        // remove(key): key存在,删除成功返回true
        // key不存在,删除失败返回false
        // key为空,抛出空指针异常
        s.remove("apple");
        System.out.println(s);
        s.remove("watermelon");
        System.out.println(s);
        // 抛出空指针异常
        // s.remove(null);
        Iterator<String> it = s.iterator();
        while(it.hasNext())
            System.out.print(it.next() + " ");
        
        System.out.println();
    

以上是关于Map和Set的主要内容,如果未能解决你的问题,请参考以下文章

C++进阶第二十篇——map和set(map和set的用法+multimap+multiset+map和set代码实现)

了解map和set的底层实现

C++STL之map和set的使用

C++STL之map和set的使用

map和set的模拟实现

Map和Set