Java 哈希表

在用树实现集合时,我们发现每次找数据都要比较很多次,太慢了。有没有说明方法能不用比较直接找到呢?哈希方法可以。

1.哈希表的介绍

哈希表又叫散列表,是通过哈希函数建立的一个数据结构。

哈希函数是什么呢?

举个例子:

我们定义一组数据{1,5,6,8,7,9};

此时哈希函数是:hash(key) = key % capacity(capacity为存储元素底层空间总的大小)。

2.冲突

还是上面的例子,如果在数据中加入了15,我们发现有问题。因为hash(15)=5跟hash(5)冲突了。对于这种用不同的 key 值,但得到了相同的哈希地址的现象我们叫冲突。

遇见冲突我们要想办法解决这个问题的,这里要明白一点,由于我们给的底层存储空间是有限的,永远无法满足所有情况,因此冲突是无法避免的,我们能做的是降低冲突率。

在哈希函数设计时,我们有几种解决方案:

1.直接定制法:在数据范围已知的情况下使用,且查找的范围比较小且连续,如:存26个字母。函数:hash(key) =  A*key + B;

2.除留余数法:地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数。哈希函数:hash(key) = key%p;

3.取满法:仅适用于做算法题中,就是直接取到给定数据范围的最大值。

 3.负载因子

先看一下网上的说法:HashMap 负载因子( load factor),也叫做扩容因子和装载因子,它是 HashMap 在进行扩容时的一个阈值,当 HashMap 中的元素个数超过了容量乘以负载因子时,就会进行扩容。默认的负载因子是 0.75,也就是说当 HashMap 中的元素个数超过了容量的 75% 时,就会进行扩容。

关于为什么负载因子是0.75,现在没有什么官方解释。

4.开散列(哈希桶)

开散列法又叫拉链法,名字通俗易懂,其结构就跟拉链一样,数组内存的是链表头节点的地址。

代码的模拟实现:

public class HashBucket {
    static class Node {
        public int key;
        public int val;
        public Node next;

        public Node(int key, int val) {
            this.key = key;
            this.val = val;
        }
    }

    public Node[] array = new Node[10];
    public int usedSize;

    public static final double DEFAULT_LOAD_FACTOR = 0.75f;

    public void push(int key,int val){
        int idx=key% array.length;
        //先判断key是否存在
        Node cur=array[idx];
        while(cur!=null){
            if(cur.key==key){
                cur.val=val;
                return ;
            }
            cur=cur.next;
        }
        //如果不存在
        Node node=new Node(key, val);

        node.next=array[idx];
        array[idx]=node;
        usedSize++;
        //看看要不要扩容
        if(doLoadFactor()>=DEFAULT_LOAD_FACTOR){
            resize();
        }
    }

    private double doLoadFactor(){
        //求当前负载因子的值
        return usedSize*1.0/ array.length;
    }

    private void resize(){
        //建立一个新的数组
        Node[] newArray = new Node[2*array.length];

        for (int i = 0; i < array.length; i++) {
            //遍历每一个节点,把节点分到新的数组里
            Node cur = array[i];
            
            while (cur != null) {
                int idx = cur.key % newArray.length;
                Node curN = cur.next;
                cur.next = newArray[idx];
                newArray[idx] = cur;
                cur = curN;
            }
        }
        
        array = newArray;
    }

    public int getVal(int key){
        int idx=key% array.length;
        Node cur=array[idx];

        while(cur!=null){
            if(cur.key==key){
                return cur.val;
            }
            cur=cur.next;
        }

        return -1;
    }
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值