一、Map
1.1 Map和Collection
- map是将键映射到值得对象,一个映射不能包含重复的键,每个键最多只能映射到一个值
- map储存的元素是成对出现的,键唯一,值可以重复
- Collection储存的元素是单独出现的,Set不可以重复,List可以重复
1.2 常用的一些功能
二、散列表的介绍
- 链表和数组都可以按照人们的意愿来排列元素的次序,他们可以说是有序的(存储的顺序和取出的顺序是一致的),但想要获取某个元素就要遍历整个线性表,浪费大量时间
- 散列表:不在意元素的顺序,能够快速的查找元素的数据
2.1 什么是散列表
在Java中,散列表由数组和链表组成。它的工作原理是为每个对象计算出一个散列码,将整个散列码与桶的数量作求余操作(或者hash&(n-1)),这个计算出的整数就是对象在散列表中的位置。
哈希表还有一个重要的属性: 负载因子(load factor),它用来衡量哈希表的 空/满 程度,一定程度上也可以体现查询的效率,计算公式为:
负载因子 = 总键值对数 / 箱子个数
负载因子越大,意味着哈希表越满,越容易导致冲突,性能也就越低。因此,一般来说,当负载因子大于某个常数(可能是 1,或者 0.75 等)时,哈希表将自动扩容。
哈希表在自动扩容时,一般会创建两倍于原来个数的箱子,因此即使 key 的哈希值不变,对箱子个数取余的结果也会发生改变,因此所有键值对的存放位置都有可能发生改变,这个过程也称为重哈希(rehash)。
哈希表的扩容并不总是能够有效解决负载因子过大的问题。假设所有 key 的哈希值都一样,那么即使扩容以后他们的位置也不会变化。虽然负载因子会降低,但实际存储在每个箱子中的链表长度并不发生改变,因此也就不能提高哈希表的查询性能。
2.2 散列冲突
有时候两个不同的对象计算出相同的hashCode,就储存在同一个桶上,这就是散列冲突。此时需要用该对象和桶上的对象进行比较。如果存在,不添加,不存在,添加。(JDK1.8中,桶的容量变成8时,会从链表变成红黑树)
如果散列表太满了,就需要对散列表再散列。创建一个新的桶,将原来的数据插入到新的桶中
装填因子(load factor)决定了什么时候扩容。负载因子越大,意味着哈希表越满,越容易导致冲突,链表变长,查询效率降低,性能也就越低。因此,一般来说,当负载因子大于某个常数(可能是 1,或者 0.75 等)时,哈希表将自动进行2倍扩容。负载因子越小,冲突发生的可能性小,但是导致散列表的稀疏程度越大,造成了空间的浪费。
三、什么是红黑树
利用二叉查找树的特性,可以快速查找到某个元素。但是如果数据是按升序或降序排列的,这是树就变成了链表。
红黑树是一种平衡树,它可以保证二叉树的均衡结构
只有遵循这些约束的才叫红黑树(背这个貌似没啥用):
- 红黑树是二叉搜索树。
- 根节点是黑色。
- 每个叶子节点都是黑色的空节点(NIL节点)。
- 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
- 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点(每一条树链上的黑色节点数量(称之为“黑高”)必须相等)。
3.1 由2-3树到红黑树
如果从代码角度去理解红黑树的旋转和变色,那么会有助于增加我们对红黑树的恐惧
构建过程:
- 合并2-节点使其变成3-节点,继续扩充3-节点,将其变成4-节点
- 从下到上,分解4-节点为3-节点...直至不能再分
- (根据此过程可以快速将画出2-3树,然后修改成红黑树)
由2-3树脑补的红黑树的颜色表示:每个节点只有一条链接指向自己(从父节点到自己),将链接的颜色保存在表示节点的Node数据类型的boolean变量color中,若为true,说明这个节点是红色的
红黑树参考资料:
- https://blog.csdn.net/chen_zhang_yu/article/details/52415077
- https://riteme.github.io/blog/2016-3-12/2-3-tree-and-red-black-tree.html#fn:red-is-left
- http://www.sohu.com/a/201923614_466939
- https://www.jianshu.com/p/37c845a5add6
- https://www.cnblogs.com/nullzx/p/6111175.html
- https://blog.csdn.net/fei33423/article/details/79132930