例如通过一种哈希函数:
此时我们想再插入一个元素 例如插入14,但是14%10=4,4号位置已经有数据了
1 哈希冲突或哈希碰撞:对于两个关键字的A和B(A!=B),即不同的关键字通过相同的哈希函数计算出相同的哈希地址。
解决方法:
1 设立合适的哈希函数
做一个面试题
class HelloWorld {
public static int Firstchar(String str)
{
Map<Character,Integer> map=new HashMap<>();
if(str==null) return -1;
for(char ch:str.toCharArray())
{ if(map.get(ch)==null)
{
map.put(ch,1);
}
else {
int count=map.get(ch);
count++;
map.put(ch,count);
}
}
for(int i=0;i<str.length();i++)
{
if(map.get(str.charAt(i))==1)
{
return i;
}
}
return -1;
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
String str=scan.nextLine();
int index=Firstchar(str);
System.out.println(index);
}
}
2 负载因子调节:存入表中的数据/表的大小,负载因子越大,冲突性就越高,当负载因子超过0.75时,那就扩容。
1)闭散列(开放地址法)
(1)线性探测:当发生哈希冲突时,如果哈希表中没有装满,说明哈希表中一定还有空余位置,那么可以把key放到下一个空位置去,从发生冲突的位置开始,依次次向后探测,直到找到下一个空位置为止
当插入数据的时候:先通过哈希函数计算到待插入元素在哈希表中的位置,如果该位置中没有元素就直接插入新元素,如果该位置中有元素就使用线性探测找到下一个空位置,直接插入元素;
但是他会容易把冲突的元素会放在一起,还不可以随意地删除元素,例如把4删掉,44查起来会受到影响
(2) 二次探测:H(i)=H(0)+i^2;
2) 开散列:哈希桶,具体代码如下
class Node
{ int data;
String val;
Node next;
public Node(int data,String val)
{ this.val=val;
this.data=data;
}
}
class myhashtable
{ Node arr1[];
Node head=null;
Node tail=null;
int count=0;
private double load=0.75;
public myhashtable() {
this.arr1 = new Node[10];
}
public void reasize()
{
Node[] arr2=new Node[2*(arr1.length)];//新创建一个数组,长度为原来长度的二倍
for(int i=0;i<arr1.length;i++)
{
Node current=arr1[i];
while(current!=null)
{ Node curentnxst=current.next;
int key=current.data%(arr2.length);
current.next=arr1[key];
arr2[key].next=current;
current=curentnxst;
}
}
this.arr1=arr2;
}
public int push(int key,String str)
{ if((1.0)*(count/arr1.length)>load)
{
reasize();
}
Node node=new Node(key,str);
int index=key%arr1.length;
Node current=arr1[index];
while(current!=null)//先遍历数组下标的整个链表,发现如果key相同,那么就更新val的值
{ if(current.data==key)
{
current.val=str;
return key;
}
current=current.next;
}
node.next=arr1[index];
arr1[index]=node;
count++;
return -1;
}
}
对于扩容来说:采用扩容之后,原来桶中的所有数据必须要进行重新哈希,要遍历原来的链表
上面我们的哈希表是整形,但如果是任意类型,怎么办,如果key是String类型,总不可以让
一个字符串来对一个数组长度求余数吧;
上代码:
class Hello{
class Node<K,V>
{
K k;
V v;
Node next;
public Node(K k, V v) {
this.k = k;
this.v = v;
}
}
public class hasntable<K,V>
{
Node arr1[];
int count=0;
public hasntable() {
Node arr2[] = (Node[])new Node[10];
}
public void reasize()
{ Node[]arr2=new Node[2*(arr1.length)];
for(int j=0;j<arr1.length;j++)
{
Node current=arr1[j];
while(current!=null)
{
Node currentnext=current.next;
int hash=current.k.hashCode();
int index=hash%arr2.length;
current.next=arr1[index];
arr1[index].next=current;
current=currentnext;
}
}
}
public void push(K k,V v)
{ if((1.0)*(count)/(arr1.length)>0.75)
{
reasize();
}
// int index=k%arr1.length;此时k为引用类型
int hash=k.hashCode();
int index=hash%arr1.length;
Node<K,V> current=arr1[index];
while(current!=null)
{
//if(current.k==k)//是引用类型不可以直接比较(虽然不报错,但是比较标胶的是地址
if(current.k.equals(k))
{
current.v=v;
return;
}
current=current.next;
}
Node<K,V> node=new Node<>(k,v);
node.next=arr1[index];
arr1[index]=node;
count++;
}
}