哈希和树的区别一个是表结构,一个是树结构
一般哈希值通过 key % arr.length 获得
可是如果哈希值相同了怎么办呢?
这就叫哈希冲突
解决哈希冲突
有两种方法:
- 闭散列:线性探测,二次探测
- 开散列:又称为哈希桶,拉链法
注意:任何情况下,哈希表都不会存满数据,数据越多,哈希冲突的概率越大,一般当负载因子大于或者等于某一个阈值(0.7)时, 就需要进行扩容
开散列:
哈希桶就是在每个表格中建立一个链表,这样在哈希冲突时就可以进行头插。
数组中存放每一个单链表的头节点,有哈希冲突的数据,会存入单链表中,相同哈希值的数据会在同一个单链表中
代码
public class HashBucket {
private static class Node {
int key;
int value;
Node next = null;
public Node (int key, int value) {
this.key = key;
this.value = value;
next = null;
}
}
private Node[] array;
private int size;
//设置负载因子不超过0.7
private static final double LOAD_FACTORY = 0.7;
public HashBucket() {
//设置是两个空位置的表
array = new Node[2];
size = 0;
}
public double loadFactory() {
return size * 1.0 / array.length;
}
//插入
public int put(int key, int value) {
//检查容量
if (loadFactory() >= LOAD_FACTORY) {
//增容
resize();
}
//插入
//1.计算哈希值
int idx = key % array.length;
//2.不能插入重复的key,首先要查看key是否已经存在,遍历当前位置的单链表
Node cur = array[idx];
while (cur != null) {
if (cur.key == key) {
int oldV = cur.value;
cur.value = value;
return oldV;
}
cur = cur.next;
}
//找到位置进行插入
cur = new Node(key, value);
cur.next = array[idx];
array[idx] = cur;
size++;
return -1;
}
private void resize() {
Node[] newArray = new Node[array.length * 2];
//元素搬移
//遍历旧表
for (int i = 0; i < array.length; i++) {
Node curHead = array[i];
while (curHead != null) {
Node next = curHead.next;
//计算当前元素在新表中的位置
int idx = curHead.key % newArray.length;
//头插
curHead.next = newArray[idx];
newArray[idx] = curHead;
curHead = next;
}
}
array = newArray;
}
public int get(int key) {
//只需要搜索表中的一个单链表即可
int idx = key % array.length;
Node cur = array[idx];
while (cur != null) {
if (cur.key == key){
return cur.value;
}
cur = cur.next;
}
return -1;
}
public int remove(int key) {
int idx = key % array.length;
Node prev = null;
Node cur = array[idx];
//删除单链表
while (cur != null) {
if (cur.key == key) {
if (prev == null) {
//删除头节点
array[idx] = cur.next;
} else {
prev.next = cur.next;
}
} else {
prev = cur;
cur = cur.next;
}
}
return -1;
}
}