Un amigo necesitaba un algoritmo que le permitiera recorrer los elementos de una matriz NxM (N y M son extraños). Se me ocurrió una solución, pero quería ver si mis compañeros SO'ers podrían encontrar una solución mejor.
Estoy publicando mi solución como respuesta a esta pregunta.
Salida de ejemplo:
Para una matriz 3x3, la salida debería ser:
(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1 )
Además, el algoritmo debería admitir matrices no cuadradas, por lo que, por ejemplo, para una matriz de 5x3, la salida debería ser:
(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1 ) (2, -1) (2, 0) (2, 1) (-2, 1) (-2, 0) (-2, -1)
Respuestas:
Aquí está mi solución (en Python):
fuente
C ++ alguien? Traducción rápida de python, publicada para completar
fuente
Ha habido muchas soluciones propuestas para este problema escritas en varios lenguajes de programación, sin embargo, todas parecen provenir del mismo enfoque intrincado. Voy a considerar el problema más general de calcular una espiral que se puede expresar de manera concisa usando inducción.
Caso base: Comience en (0, 0), avance 1 casilla, gire a la izquierda, avance 1 casilla, gire a la izquierda. Paso inductivo: Avanzar n + 1 casillas, girar a la izquierda, avanzar n + 1 casillas, girar a la izquierda.
La elegancia matemática de expresar este problema sugiere fuertemente que debería haber un algoritmo simple para calcular la solución. Teniendo en cuenta la abstracción, he optado por no implementar el algoritmo en un lenguaje de programación específico, sino como un pseudocódigo.
Primero consideraré un algoritmo para calcular solo 2 iteraciones de la espiral usando 4 pares de bucles while. La estructura de cada par es similar, pero distinta por derecho propio. Esto puede parecer una locura al principio (algunos bucles solo se ejecutan una vez), pero paso a paso haré transformaciones hasta llegar a 4 pares de bucles que son idénticos y, por lo tanto, se pueden reemplazar con un solo par colocado dentro de otro bucle. Esto nos proporcionará una solución general para calcular n iteraciones sin usar ningún condicionante.
La primera transformación que haremos es la introducción de una nueva variable d, para la dirección, que contiene el valor +1 o -1. La dirección cambia después de cada par de bucles. Dado que conocemos el valor de d en todos los puntos, podemos multiplicar cada lado de cada desigualdad por él, ajustar la dirección de la desigualdad en consecuencia y simplificar cualquier multiplicación de d por una constante a otra constante. Esto nos deja con lo siguiente.
Ahora notamos que tanto x * d como RHS son enteros, por lo que podemos restar cualquier valor real entre 0 y 1 del RHS sin afectar el resultado de la desigualdad. Elegimos restar 0.5 de las desigualdades de cada par de bucles while para establecer un patrón más.
Ahora podemos introducir otra variable m para el número de pasos que damos en cada par de bucles while.
Finalmente, vemos que la estructura de cada par de bucles while es idéntica y puede reducirse a un solo bucle colocado dentro de otro bucle. Además, para evitar el uso de números con valor real, he multiplicado el valor inicial de m; el valor m se incrementa en; y ambos lados de cada desigualdad por 2.
Esto lleva a la solución que se muestra al comienzo de esta respuesta.
fuente
Aquí hay una solución O (1) para encontrar la posición en una espiral cuadrada: Fiddle
fuente
if (n === 0) return [0, 0, r]; --n;
Ver Fiddle: jsfiddle.net/Wishmesh/nwd9gt1s/2Me encantan los generadores de Python.
Prueba con:
Usted obtiene:
fuente
Intento de "código golf" en espiral Java, basado en la variante C ++.
fuente
Aquí hay una solución C ++ que muestra que puede calcular las siguientes coordenadas (x, y) directa y fácilmente de las anteriores, sin necesidad de rastrear la dirección, el radio o cualquier otra cosa actual:
Si todo lo que intenta hacer es generar los primeros N puntos en la espiral (sin la restricción del problema original de enmascarar a una región N x M), el código se vuelve muy simple:
El truco es que puedes comparar x e y para determinar en qué lado del cuadrado estás, y eso te dice en qué dirección debes moverte.
fuente
TDD, en Java.
SpiralTest.java:
Spiral.java:
fuente
Aquí está mi solución (en Ruby)
fuente
Haskell, elige tu opción:
fuente
Esto está en C.
Por casualidad elegí nombres de variables malas. En los nombres T == arriba, L == izquierda, B == abajo, R == derecha. Entonces, tli está arriba a la izquierda iy brj está abajo a la derecha j.
fuente
Tengo una biblioteca de código abierto, pixelscan , que es una biblioteca de Python que proporciona funciones para escanear píxeles en una cuadrícula en una variedad de patrones espaciales. Los patrones espaciales incluidos son circulares, anillos, cuadrículas, serpientes y caminatas aleatorias. También hay varias transformaciones (p. Ej., Recortar, intercambiar, rotar, traducir). El problema de OP original se puede resolver de la siguiente manera
que produce los puntos
Los generadores y transformaciones de las bibliotecas se pueden encadenar para cambiar los puntos en una amplia variedad de órdenes y patrones espaciales.
fuente
Aquí hay una solución en Python 3 para imprimir enteros consecutivos en espiral en sentido horario y antihorario.
Explicación
Una espiral está hecha de cuadrados concéntricos, por ejemplo, un cuadrado de 5x5 con rotación en el sentido de las agujas del reloj se ve así:
(
>>>>>
significa "ir 5 veces a la derecha" o aumentar el índice de columna 5 veces,v
significa bajar o aumentar el índice de fila, etc.)Todos los cuadrados son iguales hasta su tamaño, recorrí los cuadrados concéntricos.
Para cada cuadrado, el código tiene cuatro bucles (uno para cada lado), en cada bucle aumentamos o disminuimos las columnas o el índice de fila. Si
i
es el índice de la fila yj
el índice de la columna, se puede construir un cuadrado de 5x5: - incrementandoj
de 0 a 4 (5 veces) - incrementandoi
de 1 a 4 (4 veces) - disminuyendoj
de 3 a 0 (4 veces) - disminuyendoi
de 3 a 1 (3 veces)Para los siguientes cuadrados (3x3 y 1x1) hacemos lo mismo pero desplazamos los índices inicial y final de manera apropiada. Usé un índice
k
para cada cuadrado concéntrico, hay n // 2 + 1 cuadrados concéntricos.Finalmente, algunas matemáticas para una bonita impresión.
Para imprimir los índices:
fuente
Aquí está c #, linq'ish.
El primer ejemplo de la pregunta (3x3) sería:
El segundo ejemplo de la pregunta (5x3) sería:
fuente
Esta es una versión ligeramente diferente, tratando de usar
recursion
yiterators
en LUA. En cada paso, el programa desciende más dentro de la matriz y los bucles. También agregué una bandera adicional a espiralclockwise
oanticlockwise
. La salida comienza desde las esquinas inferiores derecha y se repite recursivamente hacia el centro.fuente
// implementación de PHP
fuente
Aquí hay una solución iterativa de JavaScript (ES6) para este problema:
Aquí se explica cómo usarlo:
spiralMatrix(0, 0, 1, 100);
Esto creará una espiral hacia afuera, comenzando en las coordenadas (x = 0, y = 0) con el paso de 1 y un número total de elementos igual a 100. La implementación siempre comienza el movimiento en el siguiente orden: arriba, derecha, abajo, izquierda.
Tenga en cuenta que esta implementación crea matrices cuadradas.
fuente
Aquí hay una respuesta en Julia: mi enfoque es asignar los puntos en cuadrados concéntricos ('espirales') alrededor del origen
(0,0)
, donde cada cuadrado tiene longitud lateralm = 2n + 1
, para producir un diccionario ordenado con números de ubicación (comenzando desde 1 para el origen) como claves y la coordenada correspondiente como valor.Dado que la ubicación máxima por espiral es
(n,-n)
, el resto de los puntos se pueden encontrar simplemente trabajando hacia atrás desde este punto, es decir, desde la esquina inferior derecha porm-1
unidades, y luego repitiendo para los 3 segmentos perpendiculares dem-1
unidades.Este proceso está escrito en el orden inverso a continuación, correspondiente a la forma en que avanza la espiral en lugar de este proceso de conteo inverso, es decir, el
ra
segmento [ascendente derecho] se decrementa por3(m+1)
, luegola
[ascendente izquierdo]2(m+1)
, y así sucesivamente, con suerte esto se explica por sí mismo .Entonces, para su primer ejemplo, al conectarse
m = 3
a la ecuación para encontrar n dan = (5-1)/2 = 2
, ywalk(2)
le da un diccionario ordenado de ubicaciones a coordenadas, que puede convertir en solo una matriz de coordenadas accediendo alvals
campo del diccionario :Tenga en cuenta que para algunas funciones [p
norm
. Ej. ] Puede ser preferible dejar las coordenadas en matrices en lugar deTuple{Int,Int}
, pero aquí las cambio a tuplas,(x,y)
como se solicitó, utilizando la comprensión de listas.No se especifica el contexto para "soportar" una matriz no cuadrada (tenga en cuenta que esta solución todavía calcula los valores fuera de la cuadrícula), pero si desea filtrar solo al rango
x
pory
(aquí parax=5
,y=3
) después de calcular la espiral completa entoncesintersect
esta matriz contra los valores dewalk
.fuente
Su pregunta parece una pregunta llamada memoria espiral. En ese problema, cada cuadrado en la cuadrícula se asigna en un patrón en espiral a partir del número 1 que se ubica en el origen. Y luego contando en espiral hacia afuera. Por ejemplo:
Mi solución para calcular las coordenadas de cada número siguiendo este patrón en espiral se publica a continuación:
fuente
Esto se basa en su propia solución, pero podemos ser más inteligentes al encontrar las esquinas. Esto hace que sea más fácil ver cómo puede saltarse las áreas exteriores si M y N son muy diferentes.
y una solución basada en generador que es mejor que O (max (n, m) ^ 2), es O (nm + abs (nm) ^ 2) porque omite tiras enteras si no son parte de la solución.
fuente
fuente
Esta es mi muy, muy mala solución, hecha con un mínimo conocimiento de Java. Aquí tengo que colocar unidades en un campo en espiral. Las unidades no se pueden colocar encima de otras unidades o en montañas o en el océano.
Para ser claro. Esta no es una buena solución. Esta es una muy mala solución agregada para la diversión de otras personas de reírse de lo mal que se puede hacer.
Felicitaciones a cualquiera que realmente pueda leer esto
Pregunta adicional: ¿Cuál es el tiempo de ejecución de este "algoritmo"? :PAGS
fuente
Solución para AutoIt
fuente
Recientemente tuve un desafío similar en el que tuve que crear una matriz 2D y usar un algoritmo de matriz en espiral para ordenar e imprimir los resultados. Este código C # funcionará con una matriz N, N 2D. Es detallado para mayor claridad y es probable que se pueda reestructurar para satisfacer sus necesidades.
fuente
Hice este con un amigo que ajusta la espiral a la relación de aspecto del lienzo en Javascript. La mejor solución que obtuve para una evolución de imagen píxel a píxel, llenando toda la imagen.
Espero que ayude a alguien.
Puedes verlo trabajando en http://jsfiddle.net/hitbyatruck/c4Kd6/ . Solo asegúrese de cambiar el ancho y la altura del lienzo en los vars de JavaScript y en los atributos en el HTML.
fuente
Solo por diversión en Javascript:
fuente
Versión C #, también maneja tamaños no cuadrados.
fuente
Estoy compartiendo este código que diseñé para un propósito diferente; se trata de encontrar el número de columna "X" y el número de fila "Y" del elemento de matriz @ índice espiral "índice". Esta función toma el ancho "w" y la altura "h" de la matriz, y el "índice" requerido. Por supuesto, esta función se puede usar para producir la misma salida requerida. Creo que es el método más rápido posible (ya que salta sobre las celdas en lugar de escanearlas).
fuente
Código de espiral de Python en sentido horario usando la respuesta de Can Berk Güder .
fuente
La excelente solución de Davidont en VB.Net
fuente