HashMap 与 HashSet
Set
什么是 Set
Set 内部只存储 key,并且要求 key 是唯一的
方法
K 是泛型
方法 | 效果 | 返回值 |
---|---|---|
add(K key) | 添加 如果已经有 返回 false 否则就是 true | boolean flag |
remove(K key) | 移除 如果已经有 返回 false 否则就是 true | boolean flag |
contains(K key) | 判断是否有该数值 如果已经有 返回 false 否则就是 true | boolean flag |
以下列代码(HashSet)为例
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
System.out.println(set.add(1));// 1
System.out.println(set.add(12));// 2
System.out.println(set.add(1));// 3
System.out.println(set);// 4
System.out.println(set.remove(12));// 5
System.out.println(set.remove(12));// 6
}
结果
过程
Map
什么是 Map
Map 由两部分组成 : key --> value
其中 key 是唯一的不能重复 ,但是 value 是可以不唯一
所以当对同一个 key 赋予相同的值的时候,就只会保留最后一个值
内部组成(近似)
一个 map 是由多个 Entry 组成,而 一个 Entry 是由 一对 key-value 组成,关系大致如下
方法
K V 都是泛型
方法 | 效果 | 返回值 |
---|---|---|
get(K key) | 从中获取对应的值 | V value |
put(K key, V value) | 添加 如果没有重复 返回 null 重复就返回 被覆盖的值 | V value |
entrySet() | 获取 entry 的集合类,可以用 forEach 遍历 | Set<Map.Entry<K, V>> set |
keySet() | 获取 key 的集合类,可以用 forEach 遍历 | Set< K> set |
以下面代码(HashMap)为例
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
System.out.println(map.put("1", 1)); // 1
System.out.println(map.put("1", 11));// 2
System.out.println(map.put("2", 1));// 3
System.out.println(map);
}
结果
它的创建过程如下
注意
由上图可知:上面两种方法 entrySet()、keySet() 都可以 用 迭代器遍历,但是 Map 本身却不可以,因为这两种方法返回都是 Set 类型,而 Set 类型是继承 Iterable 但是 Map 是没有继承
Hash(哈希表)
需要知道的概念
名称 | 概念 |
---|---|
哈希值 | 通过 hashCode(Object o1…) 来计算,返回一个整数 |
哈希函数 | 用来计算 哈希地址 的函数,如 哈希值 % 列表长度,要求 简单、尽量使结果分散等 |
哈希地址 | 类似与列表中的下标,用于访问元素 |
冲突 | 当它们的哈希地址相同的时候 发生冲突 |
负载因子 | 元素个数 / 散列表长度 与冲突率相关,一般默认为 0.75 |
解决冲突
哈希函数都是以 关键字 % 列表长度 为例
1. 线性探测
当该元素对应的哈希地址有元素的时候,就往后找,直到该位置没有元素的时候
以下图为例
2. 二次探测
当该元素对应的哈希地址有元素的时候,新的地址就按照 (哈希地址 + i ^ 2) % len 的过程排序 。i 从 1 开始
3. 开散列/哈希桶(重点)
每个哈希地址可以不只存储 1 个元素(以链表或红黑树的方式存储)
当负载因子超出阈值的时候,就扩展并重新排序