En cuanto a la teoría, cada salida de la función amazing_hash
tiene un tamaño fijo, y se asigna a otra salida de la función hash, y otra, y así sucesivamente.
Entonces, dejando de lado la primera entrada, tiene una función desde un conjunto finito a sí mismo. La función puede o no ser biyectiva, pero no es una propiedad requerida de una función hash. El dominio de la función necesariamente se divide en:
- uno o más ciclos, más
- cero o más "colas", es decir, secuencias que conducen a uno de los ciclos o a otra cola. Cuando se unen dos colas, se considera arbitrario cuál de ellas conduce a la otra, pero luego usaré el número de colas, por lo que debe definirse de esa manera :-) Defina también el "final" de una cola para sea el punto donde se une otra cola o un ciclo.
Cada punto, cuando se itera, es parte de un ciclo para comenzar o de lo contrario sigue una cola, y las colas que se unen a la cola, hasta que se unen a un ciclo. Esa es una propiedad necesaria de una función desde un conjunto finito a sí mismo. Una ruta no puede ejecutarse para siempre sin ingresar un ciclo, porque solo hay un número finito de valores, por lo que eventualmente debe repetir uno. Por lo tanto, puedes imaginar la función visualmente como muchos círculos, con ramas sobresaliendo de los lados de ellos. Todas las ramas llevan a los círculos.
Con una iteración (es decir, un hash más después del hash inicial), ¿cuántas colisiones hay? Bueno, está relacionado con el número de colas, ya que el final de una cola es un lugar donde dos valores no iguales tienen el mismo hash. Cada punto de unión implica que hay un número de valores en colisión igual al número de estructuras que se unen en ese punto. Cada cola termina en una unión, así que si definimos "colas" y "colisiones" cuidadosamente, entonces el número de colisiones es solo la cantidad de colas.
Después de dos iteraciones, ¿cuántas colisiones hay? Es el número de colas (ya que una vez que dos valores se colisionan, permanecen colisionados), más el número de nuevas colisiones causadas por la iteración adicional. La iteración adicional provoca una colisión si "ambos lados" de un punto de unión tienen al menos 2 nodos de longitud. Entonces, cuando dos colas se unen, deben tener al menos 2 nodos de longitud, y cuando una cola se une a un ciclo, debe tener al menos 2 ciclos.
Después de n iteraciones, las colas son generadas por colas de al menos n nodos de longitud y n-ciclos.
En el caso extremo, una función hash que es biyectiva no tiene cola. Este es el teorema de las funciones finitas: cada permutación divide su dominio en ciclos. Entonces debería ser fácil ver que no importa cuántas iteraciones haga, hay no colisiones (además de las causadas por el hash inicial, por supuesto). Cada punto simplemente se mueve alrededor de su ciclo. Al mover cada punto un número igual de pasos alrededor de un ciclo, siguen todos en diferentes posiciones.
De lo contrario, para comenzar con más iteraciones que hagas, más colisiones se generan a medida que las colas se unen en los ciclos. Sin embargo, hay un límite superior para este proceso, porque cada cola y cada ciclo tienen una longitud finita. Eventualmente no causará más colisiones cuando haga más iteraciones. Eso no sucederá hasta que haya alcanzado la longitud de la cola más larga en su función.
Todo esto es en teoría: en la práctica, la cola más larga podría ser bastante más grande de lo que tienes tiempo de iterar. Si es así, seguirías aumentando el número de colisiones durante el tiempo que puedas en la práctica.
Sin embargo , el número de colisiones que introduce cada iteración es aún muy pequeño en comparación con el espacio hash, tan pequeño que es increíblemente improbable que encuentre una colisión de esta manera. Cómo sabemos esto? Porque si no lo fuera, entonces el algoritmo de búsqueda de ciclos de Floyd sería un medio eficaz para encontrar colisiones en la función hash. La función hash no sería "asombrosa" según los supuestos de la pregunta, se sabría que está rota :-)