首页 > 编程知识 正文

二维数组存储地址的计算,哈希表的存储结构

时间:2023-05-05 10:55:59 阅读:134602 作者:978

我们知道Objects定义了用于计算对象哈希值的hashcode ()函数。 而且很多类都复盖了hashcode ()函数。 但是,HashMap没有直接使用每个类的hash值,而是使用hash ()函数重新计算。

一.列举一些与基本类型对应的普通类型的hashcode ()

对象

publicstaticinthashcode (objecto ) (

返回o!=null? o.hashcode(:

}

智能手机

公共int hashcode (

returninteger.hashcode(value;

//是自己

斯汀

公共int hashcode (

int h=hash;

if(h==0value.length0) {

char val[]=value;

for(intI=0; i value.length; I ) {

h=31 * h val[i]; //

}

hash=h;

}

返回h;

//将字符串转换为字符数组,对字符的散列值进行的运算

角色

publicstaticinthashcode (char value ) {

返回(int )值;

//字符对应的asc11代码

日期

公共int hashcode (

long ht=this.getTime (;

return(int ) ht ^ (int ) ht 32;

}

二、HashMap中有hash (函数,再次计算了Objects的散列值

1 .计算方法

staticfinalinthash(objectkey ) {

int h; return(key==null )? 0:(h=key.hashcode () ) ) ) ) ) ) ) ) )。

}

重新计算的散列值是hashCode ) )计算的散列值与其自身向左移位了16位的数的异或

例如:

h=hashcode (-11110111111111111101101101110111011101

h16-00000000000011110111111

h ^ (h16 (-1111011111100101100001010=hash

2 .为什么这样计算

可以看到,哈希值是32位的二进制数字,如果将哈希值向右偏移16位,则正好为32位的一半。 也就是说,如果将自己的前16位和后16位进行异或,则在table数组的长度较小时,哈希值的高位也可以参与数组位置的计算

三.表阈值

在什么是HashMap这一节中,table的阈值并不一定是自己设定的容量负载因子,而是经过tableSizeFor () )函数的计算,由此可知该函数是什么

saticfinalinttablesizefor{

int n=cap - 1;

n |=n 1;

n |=n 2;

n |=n 4;

n |=n 8;

n |=n 16;

返回(n0 )? 1:(n=maximum_capacity? MAXIMUM_CAPACITY:n 1; }

首先,它的目的是找到最小的2的幂,它几乎等于用户给定的散列表的容量。 例如,如果用户给了7,我们就找到8,如果用户给了14,我们就需要找到16。 为什么能用这个方法找到呢? 让我看看

如果要找的数是最接近14的2的平方,那么很明显这个数是16,是2的4次方

16的二进制: 0001 0000

14的二进制数: 0000 1100

15的二进制: 0000 1111

请这样想。 我想用14计算16。 那么,你可以先计算15,然后再加1。 另一方面,15具有4个1的特征。 那么,现在的问题是14如何从其前0以外的数中将下一个数字全部转换为1。

首先14和15的第一位是0以外的数在同一位。 也就是说,不需要管理后面的数据,而只需要管理后面的数据。 用什么方法能把所有的数转换成1呢? 那是和1的进行和运算。

因此,考虑了可以将利14的第一位(或上位)的非零数和后面的数相加或运算。

Cap==14;

N=cap-1==13;

-1是为了防止如果用户提供的数本身是2的幂(如16 ),则在16-1之后仍可以//按以下方式计算期望的结果:

n |=n 1; 0000 1100

0000 0110

0000 1110

n |=n 2; 0000 1110

0000 0011

0000 1111

n |=n 4;

n |=n 8;

n |=n 16;

举个例子,在n进行了第一次或运算后,如果n的前两位变换为1,则可以使用前两位变换为3,4,位变换为1,所以在第二次和运算中n向右移动两位。 同样,在进行第二次运算后,n的前4位已经是1,可以用它们改变5、6、7、8位。 今后也一样。 所以,按照1、2、4、8、16的顺序向右移动。 那么,为什么向右移动16位后就停止了呢?

int在java中是4个子节的32比特,但是向右移动16比特的话,从上位的最初出现1的位置开始向右连续32比特变为1,已经超过了int的最大值,所以没有必要进行移位操作

方法最后把n 1变成了我们希望的2的乘方

四.根据哈希值计算数组中位置的方法

if () p=tab(I=(n-1 ) hash] ) )==null ) )

tab[I]=newnode(hash,key,value,null );

//n是数组的大小,是2的指数倍

这是putVal函数的短代码。 发现数组中的位置是用n-1和hash计算的

3.1为什么是n-1?

数组的长度n一定由2的指数倍(tableSizeFor ) )函数决定),所以n-1变换二进制时,下数位全部为1,前一位全部为0.00000000001111 ) 15 )

这样,在进行与散列值的乘积运算的情况下(在上述例子中) ) ) )。

0000 0000 0000 0000 0000 0000 0000 1111

1111 0101 1111 1111 0010 1110 0000 1010

0000 0000 0000 0000 0000 0000 0000 1010

进行与运算时,无论什么数和0与都为0,所以可以保证与运算的结果在0~n-1之间,即阵列下标的范围内,不会发生阵列越界

下一节:快速访问hashmap

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。