上一节,我们已经介绍了最重要的B树以及B+树,使用的情况以及区别的内容。当然,本节课,我们将学习重要的一个数据结构、哈希表
哈希表
哈希也常被称作是散列表,为什么要这么称呼呢,散列、散列、其元素分布较松散、经常用来储存例如key-value
的数据、这样有什么好处呢?我们来细细琢磨一下:
- 公安 110
- 急救 120
- 火警 114
假设我们需要将这几个数据保存下来,并且取出的时候,我知道公安
我就能立马查找出公安所对应的号码。并且是快速查询出?怎么做呢?
我们都知道,数组通过索引的方式,也就是下标,它的时间复杂度是最低的。O(1)
通过下标一下子就能找出来。我们有没有办法,通过我们当前的这个key
来算出hash 值呢?
这里的算
这个过程,就是一个生成索引的过程,就是我们所说的哈希(hash)
画图理解一下
假设我们的Hash 算法我们自己定义的,已知条件,所以我们随便知道一个值key
就能算出这个值存在数组的下标,所以呢 能够实现快速查询。
哈希碰撞
就是两个元素算出的hash值一样呢?就会产生冲突,这样的情况只能避免,不能消除。
HashMap
我们来看看JAVA 里面的HashMap 是怎么实现的吧;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
DEFAULT_LOAD_FACTOR= 荷载系数
默认是0.75 荷载比例大于这个数值的时候,就需要扩容了。
DEFAULT_INITIAL_CAPACITY=初始化容量大小 16
transient Node<K,V>[] table;
我们可以发现,它其中有一个table 的数组,类型是Node,很显然,这就是底层的数组,放置的数据就是这个节点包装类。
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
节点带有当前的hash值,以及键值、我们还会发现,他会带有一个next 元素的指针,这说明什么?就是单向链表呗。
put 增加一个节点
我们构造一个新的map 集合,通过put(k,v)
向散列表中增加一个节点信息。
Map<String,String> map = new HashMap<>();
map.put("key","value");
------------
public V put(K key, V value) {