stringtranslate.com

Algoritmo de Steinhaus-Johnson-Trotter

El ciclo hamiltoniano en el gráfico de Cayley del grupo simétrico generado por el algoritmo Steinhaus-Johnson-Trotter
Diagrama de rueda de todas las permutaciones de longitud generadas por el algoritmo Steinhaus-Johnson-Trotter, donde cada permutación está codificada por colores (1=azul, 2=verde, 3=amarillo, 4=rojo).

El algoritmo Steinhaus-Johnson-Trotter o algoritmo de Johnson-Trotter , también llamado cambios simples , es un algoritmo que lleva el nombre de Hugo Steinhaus , Selmer M. Johnson y Hale F. Trotter que genera todas las permutaciones de elementos. Cada dos permutaciones adyacentes en la secuencia resultante difieren al intercambiar dos elementos permutados adyacentes. De manera equivalente, este algoritmo encuentra un ciclo hamiltoniano en el permutoedro , un politopo cuyos vértices representan permutaciones y cuyas aristas representan intercambios.

Este método ya era conocido por los cambiadores ingleses del siglo XVII , y Robert Sedgewick lo llama "quizás el algoritmo de enumeración de permutaciones más destacado". [1] Se puede implementar una versión del algoritmo de tal manera que el tiempo promedio por permutación sea constante. Además de ser simple y computacionalmente eficiente, este algoritmo tiene la ventaja de que los cálculos posteriores sobre las permutaciones generadas pueden acelerarse aprovechando la similitud entre permutaciones consecutivas. [1]

Algoritmo

La secuencia de permutaciones generada por el algoritmo Steinhaus-Johnson-Trotter tiene una estructura recursiva natural , que puede generarse mediante un algoritmo recursivo. Sin embargo, el algoritmo Steinhaus-Johnson-Trotter real no utiliza recursividad, sino que calcula la misma secuencia de permutaciones mediante un método iterativo simple. Una mejora posterior le permite ejecutarse en un tiempo promedio constante por permutación.

Estructura recursiva

La secuencia de permutaciones para un número dado se puede formar a partir de la secuencia de permutaciones colocando el número en cada posición posible en cada una de las permutaciones más cortas. El algoritmo Steinhaus-Johnson-Trotter sigue esta estructura: la secuencia de permutaciones que genera consta de bloques de permutaciones, de modo que dentro de cada bloque las permutaciones coinciden en el orden de los números del 1 al y difieren sólo en la posición de . Los bloques en sí están ordenados de forma recursiva, según el algoritmo Steinhaus-Johnson-Trotter para un elemento menos. Dentro de cada bloque, las posiciones en las que se coloca ocurren en orden descendente o ascendente, y los bloques alternan entre estos dos órdenes: las ubicaciones en el primer bloque son en orden descendente, en el segundo bloque están en orden ascendente, en el tercer bloque están en orden descendente, y así sucesivamente. [2]

Así, a partir de la única permutación de un elemento,

1

se puede colocar el número 2 en cada posición posible en orden descendente para formar una lista de dos permutaciones en dos elementos,

1 2
2 1

Luego, se puede colocar el número 3 en cada una de tres posiciones diferentes para estas dos permutaciones, en orden descendente para la primera permutación 1 2, y luego en orden ascendente para la permutación 2 1:

1 2 3
1 3 2
3 1 2
3 2 1
2 3 1
2 1 3

El mismo patrón de ubicación, alternando entre ubicaciones descendentes y ascendentes de , se aplica a cualquier valor mayor de . [2] En secuencias de permutaciones con esta estructura recursiva, cada permutación difiere de la anterior ya sea por el movimiento de una sola posición a la vez o por un cambio de dos números más pequeños heredados de la secuencia anterior de permutaciones más cortas. . En cualquier caso, esta diferencia es sólo la transposición de dos elementos adyacentes. Cuando el primer y último elemento de la sucesión, además, difieren sólo en dos elementos adyacentes (las posiciones de los números y ), como puede comprobarse por inducción.

Esta secuencia puede generarse mediante un algoritmo recursivo que construye la secuencia de permutaciones más pequeñas y luego realiza todas las inserciones posibles del número más grande en la secuencia generada recursivamente. [2] El mismo orden de permutaciones también se puede describir de manera equivalente como el orden generado por el siguiente algoritmo codicioso. [3] Comience con la permutación de identidad . Ahora transponga repetidamente la entrada más grande posible con la entrada a su izquierda o derecha, de modo que en cada paso, se cree una nueva permutación que no se haya encontrado antes en la lista de permutaciones. Por ejemplo, en el caso de que la secuencia comience con , luego voltea con su vecino izquierdo para obtener . A partir de este punto, invertir con su vecino derecho produciría la permutación inicial , por lo que la secuencia cambia con su vecino izquierdo y llega a , etc. La dirección de la transposición (izquierda o derecha) siempre está determinada de forma única en este algoritmo. Sin embargo, el algoritmo Steinhaus-Johnson-Trotter real no utiliza recursividad y no necesita realizar un seguimiento de las permutaciones que ya ha encontrado. En cambio, calcula la misma secuencia de permutaciones mediante un método iterativo simple .

Versión original

Como lo describe Johnson, el algoritmo para generar la siguiente permutación a partir de una permutación dada realiza los siguientes pasos.

Cuando no se puede encontrar ningún número que cumpla las condiciones del segundo paso del algoritmo, el algoritmo ha alcanzado la permutación final de la secuencia y termina. Este procedimiento podrá implementarse en el tiempo por permutación. [4]

Trotter ofrece una implementación alternativa de un algoritmo iterativo para la misma secuencia, en notación ALGOL 60 ligeramente comentada. [5]

Debido a que este método genera permutaciones que alternan entre pares e impares, se puede modificar fácilmente para generar solo las permutaciones pares o solo las impares: para generar la siguiente permutación de la misma paridad a partir de una permutación dada, simplemente aplique el mismo procedimiento dos veces. . [6]

La aceleración de Even

Una mejora posterior realizada por Shimon Even proporciona una mejora en el tiempo de ejecución del algoritmo al almacenar información adicional para cada elemento en la permutación: su posición y una dirección (positiva, negativa o cero) en la que se está moviendo actualmente (esencialmente, esta es la misma información calculada usando la paridad de la permutación en la versión del algoritmo de Johnson). Inicialmente, la dirección del número 1 es cero y todos los demás elementos tienen una dirección negativa:

1-2-3

En cada paso, el algoritmo encuentra el elemento más grande con una dirección distinta de cero y lo intercambia en la dirección indicada:

1-3-2

Si esto hace que el elemento elegido alcance la primera o última posición dentro de la permutación, o si el siguiente elemento en la misma dirección es mayor que el elemento elegido, la dirección del elemento elegido se establece en cero:

3 1 −2

Después de cada paso, todos los elementos mayores que el elemento elegido (que anteriormente tenía dirección cero) tienen sus direcciones configuradas para indicar movimiento hacia el elemento elegido. Es decir, positivo para todos los elementos entre el inicio de la permutación y el elemento elegido, y negativo para los elementos hacia el final. Así, en este ejemplo, después de que el número 2 se mueve, el número 3 vuelve a estar marcado con una dirección:

+3 2 1

Los dos pasos restantes del algoritmo son:

2 +3 1
2 1 3

Cuando todos los números quedan sin marcar, el algoritmo finaliza. [7]

Este algoritmo toma tiempo para cada paso en el que se encuentre el mayor número a mover . Por lo tanto, los intercambios que involucran el número toman sólo un tiempo constante; Dado que estos intercambios representan todos menos una fracción de todos los intercambios realizados por el algoritmo, el tiempo promedio por permutación generada también es constante, aunque una pequeña cantidad de permutaciones tomará una mayor cantidad de tiempo. [1]

Una versión sin bucles más compleja del mismo procedimiento adecuada para la programación funcional permite realizarlo en tiempo constante por permutación en todos los casos; sin embargo, las modificaciones necesarias para eliminar los bucles del procedimiento lo hacen más lento en la práctica. [8]

Estructuras relacionadas

permutoedro

El conjunto de todas las permutaciones de elementos puede representarse geométricamente mediante un permutoedro , el politopo formado a partir de la cáscara convexa de los vectores, las permutaciones del vector . Aunque se define de esta manera en un espacio de dimensiones, en realidad es un politopo de dimensiones; por ejemplo, el permutoedro de cuatro elementos es un poliedro tridimensional, el octaedro truncado . Si cada vértice del permutoedro está etiquetado por la permutación inversa a la permutación definida por sus coordenadas de vértice, el etiquetado resultante describe un gráfico de Cayley del grupo simétrico de permutaciones en elementos, generado por las permutaciones que intercambian pares de elementos adyacentes. Así, cada dos permutaciones consecutivas en la secuencia generada por el algoritmo Steinhaus-Johnson-Trotter corresponden de esta manera a dos vértices que forman los puntos finales de una arista en el permutoedro, y toda la secuencia de permutaciones describe un camino hamiltoniano en el permutoedro, un camino que pasa por cada vértice exactamente una vez. Si la secuencia de permutaciones se completa agregando una arista más de la última permutación a la primera de la secuencia, el resultado es un ciclo hamiltoniano. [9]

Códigos grises

Un código Gray para números en una base dada es una secuencia que contiene cada número hasta un límite dado exactamente una vez, de tal manera que cada par de números consecutivos difiere en uno en un solo dígito. Las permutaciones de los números del 1 al se pueden colocar en correspondencia uno a uno con los números del 0 al emparejando cada permutación con la secuencia de números que cuenta el número de posiciones en la permutación que están a la derecha del valor y que contienen un valor menor que (es decir, el número de inversiones para las cuales es el mayor de los dos valores invertidos), y luego interpretar estas secuencias como números en el sistema numérico factorial , es decir, el sistema de bases mixtas con secuencia de bases para Por ejemplo, la permutación daría los valores , , , y . La secuencia de estos valores, da el número. Las permutaciones consecutivas en la secuencia generada por el algoritmo Steinhaus-Johnson-Trotter tienen números de inversiones que difieren en uno, formando un código de Gray para el sistema numérico factorial. [10]

De manera más general, los investigadores de algoritmos combinatorios han definido un código Gray para un conjunto de objetos combinatorios como un orden de los objetos en el que cada dos objetos consecutivos difieren en la forma mínima posible. En este sentido generalizado, el algoritmo Steinhaus-Johnson-Trotter genera un código Gray para las permutaciones mismas. [11]

Historia

El método fue conocido durante gran parte de su historia como un método para cambiar el repique de las campanas de la iglesia: proporciona un procedimiento mediante el cual se puede hacer sonar un conjunto de campanas a través de todas las permutaciones posibles, cambiando el orden de solo dos campanas por cambio. Estos llamados "cambios simples" o "caza simple" se conocían alrededor de 1621 por cuatro campanas, [12] y el método general se remonta a un manuscrito inédito de 1653 de Peter Mundy . [6] Un libro de 1677 de Fabian Stedman enumera las soluciones para hasta seis campanas. [13] Más recientemente, los timbres de cambio se han atenido a la regla de que ninguna campana puede permanecer en la misma posición durante tres permutaciones consecutivas; esta regla es violada por los cambios simples, por lo que se han ideado otras estrategias que intercambian múltiples campanas por cambio. [14]

El algoritmo lleva el nombre de Hugo Steinhaus , Selmer M. Johnson y Hale F. Trotter . Johnson y Trotter redescubrieron el algoritmo de forma independiente a principios de la década de 1960. [15] Un libro de Steinhaus de 1958, traducido al inglés en 1964, describe un rompecabezas imposible relacionado : generar todas las permutaciones mediante un sistema de partículas, cada una de las cuales se mueve a velocidad constante a lo largo de una línea e intercambia posiciones cuando una partícula supera a otra. [16] Un artículo de 1976 de Hu y Bien le dio crédito a Steinhaus por haber formulado el problema algorítmico de generar todas las permutaciones, [17] y en 1989 su libro había sido acreditado (incorrectamente) como una de las publicaciones originales del algoritmo. [18]

Ver también

Notas

  1. ^ abc Sedgewick (1977).
  2. ^ abc Lenstra y Rinnooy Kan (1979); Salvaje (1997), sección 3; Pájaro (2010).
  3. ^ Williams (2013).
  4. ^ Johnson (1963).
  5. ^ Trotón (1962).
  6. ^ ab Knuth (2011).
  7. ^ Incluso (1973).
  8. ^ Ehrlich (1973); Dershowitz (1975); Sedgewick (1977); Pájaro (2010).
  9. ^ Véase, por ejemplo, la sección 11 de Savage (1997).
  10. ^ Dijkstra (1976); Knuth (2011).
  11. ^ Salvaje (1997).
  12. ^ Blanco (1996).
  13. ^ Stedman (1677); para obtener listas de cambios sencillos en hasta seis campanas, consulte las páginas 48 a 80.
  14. ^ McGuire (2003); Knuth (2011).
  15. ^ Johnson (1963); Trotón (1962).
  16. ^ Steinhaus (1964).
  17. ^ Hu y Tien (1976).
  18. ^ Ruskey (1989).

Referencias