Map和Set
Posted ohana!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Map和Set相关的知识,希望对你有一定的参考价值。
目录
一,搜索
1.概念和场景
- Map和set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关。以前常见的搜索方式有:
- 直接遍历,时间复杂度为O(N),元素如果比较多效率会非常慢
- 二分查找,时间复杂度为 ,但搜索前必须要求序列是有序的
- 上述排序比较适合静态类型的查找,即一般不会对区间进行插入和删除操作了
- 现实问题中的查找都存在动态查找的可能,因此,Map和Set是一种适合动态查找的集合容器
2. 模型
一般把搜索的数据称为关键字(Key),和关键字对应的称为值(Value),将其称之为Key-value的键值对,所以模型会有两种:
- 纯 key 模型
- 有一个英文词典,快速查找一个单词是否在词典中
- 快速查找某个名字在不在通讯录中
- Key-Value 模型
- 统计文件中每个单词出现的次数,统计结果是每个单词都有与其对应的次数:<单词,单词出现的次数>
- 同一个名字的使用人数,就是名字重复的人数:<名字,重复的人数>
- 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底层结构 | TreeMap | HashMap |
底层结构 | 红黑树 | 哈希桶 |
插入/删除/查找时间复杂度 | 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底层结构 | TreeSet | HashSet |
底层结构 | 红黑树 | 哈希桶 |
是否有序 | 关于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代码实现)