Hash表

1. 简述

       hash表即散列表,实际是应对直接寻址技术(数组)局限性而设计的一种数据结构。通过hash函数 h(K) 将数据映射到一个较小的地址范围。

       通过hash函数映射的地址不可避免会发生冲突,即哈希碰撞。通常可以通过链接法和开放寻址法解决。

      链接法:同一位置元素放在一个链表中,一次查找时间复杂度O(1+链表长度)

      开放寻址:发生冲突时查找下一个空槽放置,使用辅助探查函数h'(k)探查槽,如果冲突再使用探查函数探查

  • 线性探查:h(k,i)= ( h'(k) + i ) mod m
  • 二次探查:h(k,i) = ( h'(k) + ai + bi^2 ) mod m
  • 双重散列:h(k,i) = ( h'(k) + ih''(k) ) mod m

       除法散列法 h(k) = k mod m,k为关键字,m为散列表大小。m不取2的幂且尽量远离。

       乘法散列法 h(k) = m(kA mod 1),m一般取2的幂,0<A<1,A=(√5 - 1)/2=0.618...比较理想。

       全域散列法,从一组精心设计的散列函数中随机选择。

2. java中的应用

a. HashSet、LinkedHashSet、HashMap、LinkedHashMap都是使用HashMap中的散列函数

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        //(对象的hash code) 异或 (对象的hash code无符号右移16位)
    }

 数组下标i=(n-1) & hash,如下HashMap.putVal()方法

使用链接法解决冲突

b. ConcurrentHashMap是线程安全的,散列函数如下

static final int spread(int h) {
        //h=key.hashCode()
        //static final int HASH_BITS = 0x7fffffff;
        return (h ^ (h >>> 16)) & HASH_BITS;
    }

数组下标i=(n-1) & hash,如下ConcurrentHashMap.putVal()方法 

c. HashTable同样是线程安全的

int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
Entry<K,V> entry = (Entry<K,V>)tab[index];
//其中tab.length是数组长度,会有自动扩容逻辑
//扩容逻辑在HashTable.rehash()方法中,如下语句即原容量*2+1
int newCapacity = (oldCapacity << 1) + 1;

其中entry是HashTable.Entry<K,V>内部类对象,具有链表结构,解决hash冲突

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值