哈希表

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;
}

}
 

 

 

 

posted @ 2022-09-11 19:06  possiblely  阅读(204)  评论(0)    收藏  举报