0
点赞
收藏
分享

微信扫一扫

哈希表(面试常见)---数据结构(增删查改时间复杂度为O(1))

进击的铁雾 2022-03-15 阅读 74

例如通过一种哈希函数:

此时我们想再插入一个元素 例如插入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++;
    }
}

举报

相关推荐

0 条评论