哈希表
1 概念
1.1 哈希表
1.可以不经过比较,一次从表中获得想要的元素
2.哈希方法中使用的转换函数成为哈希(散列)函数,构造出来的结构称为哈希(散列)结构
哈希函数的设置一般是 hash(key) = key % capacity;
1.2 冲突概念
不同关键字通过相同哈希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。(例如 14,24,34)
1.3哈希函数设计
哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1之间
常见的函数方法:
直接定制法 除留余数法
1.4负载因子调节
负载因子=填入表中的数量/散列表的长度
如图我们可以看出负载因子越大冲突越大,所以我们要降低冲突,通过增加散列表的长度来降低冲突

1.5 冲突解决
常用的两种方法时闭散列和开散列
1.6冲突解决 闭散列
1 线性探测
插入44 如果后续有14 24 34要插入相同的哈希位置时,从发送冲突的位置开始,知道有空位就放进去
2 二次探测
为了避免冲突数据都在一起,采用二次探测通过找下一个空位置的方法为:Hi = (H0+i2 )% m
注意
当表的长度为质数且表装载因子a不超过0.5时,新的表项一定能够插入,而且任何一个位置都不
会被探查两次。因此只要表中有一半的空位置,就不会存在表满的问题。在搜索时可以不考虑表装满的情
况,但在插入时必须确保表的装载因子a不超过0.5,如果超出必须考虑增容。
1.7 开散列/哈希桶

哈希桶实现
public class HashBuck3 {
static class Node{
public int val;
public int key;
public Node next;
public Node(int key,int val){
this.key=key;
this.val=val;
}
}
public Node[] Arr;
public int usedSize;
//定义影响因子
public static final double LOAD_FACTOR=0.75;
public HashBuck3(){
this.Arr =new Node[10];
}
public void put(int key,int val){
//1 找到Key的位置
int index=key % Arr.length;
Node cur= Arr[index];
//2 遍历下标有无一样的元素
for (int i = 0; i < Arr.length ; i++) {
while (cur!=null){
if (cur.key==key){
cur.val=val;
return;
}
cur=cur.next;
}
}
//3 头插法
Node node=new Node(key, val);
node.next= Arr[index];
Arr[index]=node;
usedSize++;
//4 插入成功后检查负载因子
if (LoadFactor()>LOAD_FACTOR){
//扩容
resize();
}
}
//计算负载因子
public double LoadFactor(){
return 1.0*usedSize / Arr.length;
}
//扩容头插
public void resize(){
Node[] newArr=new Node[Arr.length*2];
for (int i = 0; i <Arr.length ; i++) {
Node cur=newArr[i];
while (cur!=null){
//将cur头插
int index= cur.key % newArr.length;
Node curNext=cur.next;
cur.next=newArr[index];
newArr[index]=cur;
cur=curNext;
}
}
Arr=newArr;
}
public int get(int key){
int index=key % this.Arr.length;
Node cur=Arr[index];
while (cur!=null){
if (cur.key==key){
//更新val
return cur.val;
}
cur=cur.next;
}
return -1;
}
}


浙公网安备 33010602011771号