Map集合
1. Map介绍
1.1 为什么需要Map
Set集合是为了存储对象,快速查找而产生的,类似对象数组。而Map不同,Map的结构在官方的解释中被称为——“映射”。
映射的模型是一个Key对应一个Value,用Key来区别不同的Value。
比如,作为学生来说,根据学号可以区分不同的学生,只要知道学号,就可以获取对应的学生信息。比如身份证,通过身份证(key)就可以证明自己(value)。
1.2 Map与Collection的区别
Map集合的特点:将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值
Map和Collection集合的区别:
- Map集合存储元素是成对出现的,Map的键是唯一的,值可以是重复的
- Collection集合存储元素是单独出现的,Collection的儿子Set是唯一的,List是可重复的
要点:
- Map集合的数据结构针对键有效,跟值无关
- Collection集合的数据结构针对元素有效
1.3 Map的功能
-
添加功能
V put(K key,V value) 添加元素
如果键是第一次存储,就直接存储元素,返回null
如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值。
-
删除功能
void clear():移除所有的键值对元素
V remove(Object key):根据键删除值,并把值返回
-
判断功能
boolean containsKey(Object key):判断集合是否包含指定的键
boolean containsValue(Object value):判断集合是否包含指定的值
boolean isEmpty():判断集合是否为空
-
获取功能
Set<Map.Entry<K key,V value>> entrySet():返回的是键值对对象的集合
V get(Object key):根据键获取值
Set<K> keySet():获取集合中所有的键的集合
Collection<V> values():获取集合中所有值的集合
-
长度功能
int size():返回集合中键值对的数量
Map中重要的子类:
- HashMap
- TreeMap
- LinkedHashMap
- ConcurrentHashMap
2. 散列表介绍
无论是Set还是Map,我们会发现都有对应的HashSet和HashMap
传统意义上来说,数组和链表都是有序的(存储顺序和取出顺序是一致的),但同时,这也是缺点,想要获取某个元素的时候,需要访问所有的元素,直到找到为止,这会浪费很多时间用来遍历。
因此,需要一种不在意存储顺序,可以快速查找的数据结构,其中最常见的就是,散列表
2.1 散列表工作原理
散列表为每个对象计算出一个整数,称为散列码。根据这些计算出来的整数(散列码)保存在对应的位置上。
在java中,散列表用的是数组加链表实现的,每个位置称之为桶。
一个桶上可能会遇到被占用的情况(hashCode散列码相同,就会存储在同一个位置上),这种情况是无法避免的,这种现象称之为:散列冲突。
- 此时需要用该对象与桶上的对象进行比较,看看该对象是否存在桶子上了,如果存在就不添加了,如果不存在,则添加到桶子上。
- 如果hashCode函数设计的足够好,桶的数目也足够,这种比较是很少的
- 在JDK1.8中,桶满时会从链表变成平衡二叉树
如果散列表太满,是需要对散列表再散列,创建一个桶数更多的散列表,并将原有的元素插入到新表中,丢掉原来的表。
- 装填因子(load factor),也称为阈值决定了合适对散列表再散列
- 装填因子默认为0.75,如果表中超过75%的位置已经填入了元素,那么这个表就会用双倍的桶数自动进行再散列
3. 红黑树介绍
在JDK1.8中,Map的桶满时会从链表变成平衡二叉树。而这里的平衡二叉树,指的就是红黑树,并且,我们的TreeSet、TreeMap的底层都是用红黑树来实现的。
AVL树: 最早的平衡二叉树之一。应用相对其他数据结构比较少。windows对进程地址空间的管理用到了AVL树。
红黑树: 平衡二叉树,广泛用在C++的STL中。如map和set都是用红黑树实现的。
B/B+树: 用在磁盘文件组织 数据索引和数据库索引。
Trie树(字典树): 用在统计和排序大量字符串,如自动机。
红黑树的由来:
- 从传统的二叉树来看,这种二叉树有一个极大的弊端,当左右二叉树存储一个升序的数组时,二叉树的结构就变成了一条链表,这根本体现不出树的优势。
- 于是,从左右二叉树中改进出了平衡二叉树,每次操作时进行平衡操作,它可以保证二叉树基本符合**矮矮胖胖(均衡)**的结构
- 平衡二叉树的基础是2-3树,它使用了2结点和3结点的相互转换,实现了树的平衡
- 但是2-3树为了保持平衡,需要大量的结点交换,这些交换针对不同的结点需要的代码实现也不同,很复杂,因此在2-3树的基础上发明了红黑树
- 红黑树是对2-3查找树的改进,它能用一种统一的方式完成所有变换。通过红色节点和黑色节点来实现2-3数中的2结点和3结点。
红黑树是在2-3树的基础上实现的一种树,它能够用统一的方式完成所有变换。红黑树也是平衡树的一种,在插入元素的时候它也得保持树的平衡。
红黑树同2-3树一样,也是用两种方式来替代2-3树不断的结点交换操作:
- 旋转:顺时针旋转和逆时针旋转
- 反色:交换红黑的颜色
- 这两个实现比2-3树交换的结点(合并,分解)要方便一些
红黑树为了保持平衡,还有指定一些约束,遵守这些约束的才能叫做红黑树:
- 红黑树是二叉搜索树
- 根结点是黑色
- 每个叶子结点都是黑色的空结点(null结点)
- 每个红色结点的两个子结点都是黑色 (从每个叶子到根的所有路径上不能有两个连续的红色结点)
- 从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点 (每一条树链上的黑色结点数量(称之为“黑高”)必须相等)