对Hash认识

本文深入解析哈希算法的核心概念,包括冲突解决策略和Java HashTable的具体实现细节。通过实例解释如何使用哈希函数分配唯一映射值,以及在面对数据冲突时采用链表辅助解决的方法。同时,详细介绍了Java HashTable中的rehash方法,包括容量扩展、阈值调整和元素迁移过程,揭示其如何高效地管理大量数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       Hash是各种程序语言中经常用到的一个“算法”或者说“结构”,按我的理解,hash就是把大量的数据打乱,对每一个数据分配一个唯一的映射值,然后重新储存,对于每一个关键字Value,都有一个映射值Key对应,既通过唯一的f(key)可以找到value;

       在每次通过key查找的时候就可以通过常数级时间查到我们所需要的对象,是一个用空间换时间的典型例子,这Hash最主要的部分当然是用一个算法(哈希函数)来分配每一个Value的映射值(就是f(key)),这里有一个例子,假设有一个从1-100岁的人口数据统计表,我们就可以把年龄当做key,hash函数就去key自身,那么当我们要查20岁的有多少人,就可以直接查表第20项;或者我们也可以把hash函数取key的某个整数的模,同样我们查找的时候根据key和hash算法的逆求出value所在位置;

       那么我们就要解决另外一个问题了,就像上面的图片右边,data会有重复的f(key)值,就造成分配冲突,这个时候 我们可以再横向的建立一个链表,把冲突的f(key)放到后面去,就向上面说的;当然,这个方法肯定不是一个好的方法,当冲突的数量达到一定的程度的时候,就完全抹掉了hash的优点,甚至变成了累赘;一个好的hash函数当然是这个好的hash函数的前提,但是对于现在的TB级大数据,hash肯定会有冲突,那就要rehash;下面介绍一下java的HashTable里面的rehash方法

protected void rehash() {
        int oldCapacity = table.length;
        //元素
        Entry<K,V>[] oldMap = table;

        int newCapacity = (oldCapacity << 1) + 1; //新容量=旧容量 * 2 + 1
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            if (oldCapacity == MAX_ARRAY_SIZE)
                return;
            newCapacity = MAX_ARRAY_SIZE;
        }
        
      
        Entry<K,V>[] newMap = new Entry[];  //新建一个size = newCapacity 的HashTable

        modCount++;//这个先不管它
        //重新计算阀值
        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
        //重新计算hashSeed
        boolean rehash = initHashSeedAsNeeded(newCapacity);

        table = newMap;
        //将原来的元素拷贝到新的HashTable中
        for (int i = oldCapacity ; i-- > 0 ;) {
            for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
                Entry<K,V> e = old;
                old = old.next;

                if (rehash) {
                    e.hash = hash(e.key);
                }
                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
                e.next = newMap[index];
                newMap[index] = e;
            }
        }
    }

可以看到,HashTable里面是把Entry的容量扩大,然后把原来的数据重新copy进去,这个是一个十分耗时间的过程,hashseed是用计算key的hash值,把它和hashcode进行按位异或运算,hashcode这个东东也有的研究,等我深究一下下再写出来跟大家分享一下,暂时可以理解成是物理地址,回过去说hashseed事实上就是用于解决冲突的。还有阙值threshold,它是用来判断是否需要rehash,这里阙值的大小要跟随HashTable的Capacity(容量)来改变,初始的阙值因子是0.75,假设我们原先初始值11、加载因子默认0.75,那么这个时候阀值threshold=8,当容器中的元素达到8时,HashTable进行一次扩容操作,容量 = 8 * 2 + 1 =17,而阀值threshold=17*0.75 = 13,当容器元素再一次达到阀值时,HashTable还会进行扩容操作,一次类推。

 

       解决冲突的方法不止一种,对于相对较少的数据可以用hashtable里面的那一种。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值