¿Por qué la longitud de HashMap es una potencia de 2? ¿Por qué el hash desplaza el XOR de 16 bits a la derecha?

1. Da la respuesta primero:

为了能让 HashMap *存取高效*,进一步降低hash冲突的几率,尽量较少碰撞,也就是要尽量把数据分配均匀。

2. Conocimiento previo:

2.1 ¿Por qué la longitud es una potencia de 2?

HashMap puede especificar la capacidad inicial. Cuando no se especifica la capacidad inicial, el valor predeterminado es 16 y se duplicará cada vez que se amplíe la capacidad. Al especificar la capacidad inicial, utilice la potencia de 2 de la capacidad inicial como la capacidad de HashMap.

Antes de JDK1.8, la capa inferior de HashMap era una matriz y una lista enlazada, que se usaban juntas para formar un hash de lista enlazada.
Después de JDK1.8, la capa inferior de HashMap es matriz + lista enlazada + árbol rojo-negro , lo que acelera aún más el proceso de búsqueda.

El proceso de posición del objeto hash HashMap se divide en 3 pasos:
1) Obtener el código hash de la clave: h=key.hashCode()
2) XOR el valor hash obtenido con el valor desplazado a la derecha sin signo de h: valor hash Igual a ( h = key.hashCode()) ^ (h >>> 16);
3) Realice una operación AND bit a bit en el resultado XOR del paso 2) y la longitud de la matriz menos 1 para obtener el subíndice: int index = ( n - 1) y hash . Si ya hay un elemento en el subíndice, se juzga si el valor hash y la clave del elemento y el elemento a almacenar son los mismos, y si son los mismos, se cubren;

Debido a que el tipo int es de 32 bits, el valor del rango en la computadora binaria es -2 31 a 2 31 -1, por lo que el valor del rango del valor Hash es -2147483648 a 2147483647. El espacio de mapeo total es de aproximadamente 4 mil millones. Siempre que la función hash se mapee de manera uniforme y suelta, es difícil que ocurran colisiones en aplicaciones generales. Pero el problema es que una matriz con una longitud de 4 mil millones no cabe en la memoria. Entonces, este valor hash no se puede usar directamente.

Antes de usarlo, realice la operación de módulo hash % longitud sobre la longitud de la matriz , y el resto obtenido es el subíndice de la matriz. Sin embargo, la eficiencia de calcular el % restante en la computadora no es tan buena como la operación de bit & , y el código fuente ha sido optimizado para hash & (longitud - 1) . Sin embargo,

hash % length == hash & (length - 1)的前提是 length 是 2的n次方。

El motivo es el siguiente:
Operación AND bit a bit & : primero convierta el valor en binario, si hay 0, será 0, si todo 1 es 1,
si la longitud de HashMap es impar , entonces longitud-1 es par, y el último dígito del número par es 0, el último dígito de hash & (longitud - 1) debe ser 0, que es un número par. En este momento, cualquier valor hash solo se puede reducir a la posición del subíndice , lo que desperdicia espacio y aumenta las colisiones.

Si la longitud length del HashMap es un número par , entonces length-1 es un número impar, el último dígito del número impar es 1 y el último dígito de hash & (longitud - 1) depende del valor hash . igualmente.

Por lo tanto, la longitud se toma como una potencia de 2, de modo que los elementos se puedan codificar uniformemente en la tabla hash, de modo que la probabilidad de colisión entre diferentes valores hash sea pequeña.

2.2 ¿Por qué se debe desplazar el hash a la derecha mediante XOR de 16 bits? h >>> 16

O la operación ^ : diferente es 1, lo mismo es 0, que puede conservar mejor las características de cada parte (01 tiene todos los cambios)

h >>> 16 : Significa mover el valor binario de h a la derecha en 16 bits, porque int es de 32 bits, luego, después de cambiar a la derecha en 16 bits, significa cambiar los 16 bits altos a los 16 bits bajos, y los 16 bits altos son todos 0 arriba.
(h = key.hashCode()) ^ (h >>> 16) : Significa usar los 16 bits superiores y los 16 bits inferiores para la operación XOR. Deje que el bit alto también participe en la operación para reducir la colisión.

? Entonces, ¿por qué no usar & o |, sino usar ^?
El valor calculado por la operación & estará más cerca de 1, y el valor calculado por la operación | estará más cerca de 0, y ^ puede retener mejor las características de cada parte.

Supongo que te gusta

Origin blog.csdn.net/weixin_45463572/article/details/130414956
Recomendado
Clasificación