哈希表 HashTable
哈希表的概念
哈希表的实现方式
数组 vs 链表
数组
- 寻址容易,插入和删除元素困难
链表
- 寻址困难,插入和删除元素容易
哈希表: 数组 + 链表
图左侧竖项为数组,每个数组的值为链表。
插入键值对演示
X => f(X) = M => M % Array.length => Position
哈希函数 (Hash Function)
哈希函数能快速将一个数值转换成哈希值(整数)。所以哈希表必须保持哈希值的计算一致,如果两个哈希值是不相同的,那么这两个哈希值的原始输入也是不相同的。
那如果两个不同的输入得到相同的哈希值 = 哈希值冲突
我们输入关键字 x, 使用哈希函数 f(x) 计算出哈希值 y, 然后使用哈希值 y 来找到特定的数组下标,并在对应位置插入新数据。
X => f(X) = Y => Y % Array.length => Array position of X
插入键值对的过程详解
哈希表支持的操作
- add(Key key, Value value): 将一对新的键值对加入哈希表
- get(Key key): 通过特定的关键字拿到其所对应的数值
- remove(Key key): 通过关键字,删除哈希表中的数值对
- getSize(): 当前键值对的数量
- isEmpty(): 查看哈希表是否为空
代码实现
import java.util.ArrayList;
public class HashMap {
static class HashNode<String, Integer> {
String key;
Integer value;
HashNode<String, Integer> next;
public HashNode(String key, Integer value) {
this.key = key;
this.value = value;
}
}
private ArrayList<HashNode<String, Integer>> bucketArray;
private int numBuckets;
private int size;
public HashMap() {
bucketArray = newArrayList<>();
numBuckets = 10;
size = 0;
for (int i = 0; i < numBuckets; i++) {
bucketArray.add(null);
}
}
private int getBucketIndex(String key) {
int hashCode = key.hashCode();
int index = hashCode % numBuckets;
return index;
}
public void add(String key, Integer value) {
int bucketIndex = getBucketIndex(key);
HashNode<String, Integer> head = bucketArray.get(bucketIndex);
while(head != null) {
if(head.key.equals(key)) {
head.value = value;
return;
}
head = head.next;
}
head = bucketArray.get(bucketIndex);
HashNode<String, Integer> newNode = new HashNode<String, Integer>(key, value);
newNode.next = head;
bucketArray.set(bucketIndex, newNode);
size++;
// 扩充条件
if((1.0 * size) / numBuckets >= 0.7) {
generateBiggerArray();
}
}
private void generateBiggerArray() {
ArrayList<HashNode<String, Integer>> temp = bucketArray;
bucketArray = new ArrayList<>();
numBuckets = 2 * numBuckets;
for (int i = 0; i < numBuckets; i++) {
bucketArray.add(null);
}
size = 0;
for (HashNode<String, Integer> headNode : temp) {
while(headNode != null) {
add(headNode.key, headNode.value);
headNode = headNode.next;
}
}
}
public Integer get(String key) {
int bucketIndex = getBucketIndex(key);
HashNode<String, Integer> head = bucketArray.get(bucketIndex);
wihile(head != null) {
if(head.key.equals(key)) {
return head.value;
}
head = head.next;
}
return null;
}
public Integer remove(String key) {
int bucketIndex = getBucketIndex(key);
HashNode<String, Integer> head = bucketArray.get(bucketIndex);
HashNode<Stirng, Integer> prev = null;
while(head != null) {
if(head.key.equals(key)) {
break;
}
prev = head;
head = head.next;
}
if(head == null) {
return null;
}
if(prev != null) {
prev.next = head.next;
} else { // Corner case: Delte the head node
bucketArray.set(bucketIndex, head.next);
}
size--;
return head.value;
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
}
来源
- 哈希表 HashMap【数据结构和算法入门 6】: https://www.youtube.com/watch?v=hERepKv2Wn4&list=PLV5qT67glKSGFkKRDyuMfwcL-hwXOc4q_&index=6