¿Qué es un hash?
Hash, generalmente traducido como "hash", hay transliteración directa como "hash", que es convertir cualquier longitud de entrada a través de un algoritmo hash a una salida de longitud fija, la salida es el valor hash (valor hash) ; Esta conversión es un mapeo de compresión, es decir, el espacio del valor hash suele ser mucho más pequeño que el espacio de entrada, las diferentes entradas pueden dividirse en la misma salida, por lo que es imposible determinar de forma exclusiva el valor de entrada a partir del valor hash . En pocas palabras, es una función que comprime cualquier longitud de mensaje a una cierta longitud de resumen de mensaje.
Todas las funciones hash tienen las siguientes características básicas: si los valores hash calculados de acuerdo con la misma función hash son diferentes, entonces el valor de entrada también debe ser diferente. Sin embargo, si los valores hash calculados a partir de la misma función hash son los mismos, los valores de entrada no son necesariamente los mismos.
¿Qué es una colisión hash?
Cuando dos valores de entrada diferentes calculan el mismo valor hash de acuerdo con la misma función hash, lo llamamos colisión (colisión hash) o colisión hash.
HashMap
Estructura de datos
En Java, hay dos estructuras de datos relativamente simples para guardar datos: matrices y listas vinculadas. Las características de la matriz son: direccionamiento fácil, difícil de insertar y eliminar; las características de la lista vinculada son: difícil de direccionar, pero fácil de insertar y eliminar . Por lo tanto, combinamos la matriz y la lista vinculada para aprovechar las dos, y utilizamos un método llamado método de dirección de cadena para resolver el conflicto de hash: de
modo que podamos organizar objetos con el mismo valor de hash en una lista vinculada. hash
correspondiente al valor bucket
más bajo, pero en comparación con el hashCode
tipo de retorno int, nuestro HashMap
tamaño capacidad inicial DEFAULT_INITIAL_CAPACITY = 1 << 4
(es decir, el cuarto lado 16 2) es mucho menor que el int
rango del tipo, si simplemente usamos hashCode
I para obtener el correspondiente tomar bucket
esta Aumentará en gran medida la probabilidad de colisión de hash y, en el peor de los casos, se HashMap
convertirá en una lista vinculada individualmente, por lo que debemos hashCode
hacer ciertas optimizaciones.
hash()
Función
El problema mencionado anteriormente se debe principalmente a que si hashCode
toma el resto, entonces el único hashCode
bit bajo equivalente a participar en la operación , el bit alto no juega ningún papel, por lo que nuestra idea es dejar que hashCode
el bit alto del valor también participe en la operación, reduciendo aún más hash
La probabilidad de colisión hace que la distribución de datos sea más uniforme. Llamamos a esta operación una perturbación. JDK 1.8
La hash()
función en es la siguiente:
static final int hash(Object key) {
int h;
// 与自己右移16位进行异或运算(高低位异或)
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
Esto es JDK 1.7
más conciso que en. En comparación con las operaciones de 4 bits en 1.7, 5 operaciones XOR (9 perturbaciones), en 1.8, solo operación de 1 bit y 1 operación XOR (2 Disturbios).
JDK1.8
Agregar árbol rojo negro
A través del método de dirección de cadena anterior (usando una tabla hash) y la función de perturbación, hemos logrado que nuestra distribución de datos sea más uniforme, y la colisión hash se reduce, pero cuando HashMap
hay una gran cantidad de datos en la nuestra, agregar una bucket
de nuestras listas correspondientes tiene n
un elemento luego atravesar el tiempo de complejidad es O(n)
, con el fin de abordar esta cuestión, JDK 1.8
en HashMap
la nueva estructura de datos de árbol rojo-negro, haciendo reducido aún más para atravesar la complejidad O(logn)
.
Resumen
Un breve resumen de los métodos utilizados por HashMap para resolver eficazmente los conflictos hash:
- Use el método de dirección de cadena (usando una tabla hash) para vincular datos con el mismo valor hash;
- Use la función de perturbación 2 veces (función hash) para reducir la probabilidad de colisión hash, haciendo que la distribución de datos sea más uniforme;
- La introducción de árboles rojo-negros reduce aún más la complejidad temporal del recorrido y hace que el recorrido sea más rápido;