¿Cómo resuelve HashMap los conflictos hash?

¿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.

HashMapEstructura 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
Inserte la descripción de la imagen aquí
modo que podamos organizar objetos con el mismo valor de hash en una lista vinculada. hashcorrespondiente al valor bucketmás bajo, pero en comparación con el hashCodetipo de retorno int, nuestro HashMaptamaño capacidad inicial DEFAULT_INITIAL_CAPACITY = 1 << 4(es decir, el cuarto lado 16 2) es mucho menor que el intrango del tipo, si simplemente usamos hashCodeI para obtener el correspondiente tomar bucketesta Aumentará en gran medida la probabilidad de colisión de hash y, en el peor de los casos, se HashMapconvertirá en una lista vinculada individualmente, por lo que debemos hashCodehacer ciertas optimizaciones.

hash()Función

El problema mencionado anteriormente se debe principalmente a que si hashCodetoma el resto, entonces el único hashCodebit bajo equivalente a participar en la operación , el bit alto no juega ningún papel, por lo que nuestra idea es dejar que hashCodeel bit alto del valor también participe en la operación, reduciendo aún más hashLa 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.8La 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.7má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

Inserte la descripción de la imagen aquí
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 HashMaphay una gran cantidad de datos en la nuestra, agregar una bucketde nuestras listas correspondientes tiene nun elemento luego atravesar el tiempo de complejidad es O(n), con el fin de abordar esta cuestión, JDK 1.8en HashMapla 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:

  1. Use el método de dirección de cadena (usando una tabla hash) para vincular datos con el mismo valor hash;
  2. 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;
  3. 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;
Publicado 94 artículos originales · me gusta 0 · visitas 722

Supongo que te gusta

Origin blog.csdn.net/qq_46578181/article/details/105412061
Recomendado
Clasificación