Invertir una matriz sin usar iteración

Me hicieron una pregunta hoy y no creo que sea posible, pero podría estar equivocado o estoy pensando demasiado. ¿Cómo puede revertir una matriz sin usar la iteración en C?

Mi opinión es que es imposible por el hecho de que la matriz puede ser de cualquier tamaño y que ningún programa en C se puede expresar con ese tipo de soporte en mente sin usar algún tipo de iteración.

preguntado el 04 de julio de 12 a las 05:07

¿Era una pregunta de clase? pregunta de la entrevista? ¿Pregunta general del rompecabezas? -

Un ejemplo es probablemente una buena idea: { 0, 1, 2, 3, 4 } se convierte en { 4, 3, 2, 1, 0 } en la memoria. -

+1. Puede ser imposible. Pero necesitamos alguna prueba o un grupo de personas para confirmar si es posible o no. :) -

Esto se reducirá principalmente a definiciones, como exactamente qué cae/no cae dentro de la "iteración". -

La iteración aquí se refiere a para(;;)/mientras(), como pienso. Así que la recursividad podría ser la solución. Si vamos a referirnos a Iteración como accediendo a todos los elementos, entonces es imposible. -

7 Respuestas

La respuesta a tu pregunta es que, sí, es posible invertir una matriz sin iteración. La redacción de la pregunta en sí puede ser ambigua, sin embargo, el espíritu de la pregunta es obvio: se puede usar un algoritmo recursivo; y no hay ambigüedad en absoluto en cuanto al significado de recursiva En este sentido.

Si, en una situación de entrevista con una empresa de primer nivel, le hicieran esta pregunta, entonces el siguiente pseudocódigo sería suficiente para demostrar que verdaderamente entendido lo que se entiende por recursividad:

function reverse(array)

    if (length(array) < 2) then
        return array

    left_half = reverse(array[0 .. (n/2)-1])
    right_half = reverse(array[(n/2) .. (n-1)])

    return right_half + left_half

end

Por ejemplo, si tenemos una matriz de 16 elementos que contienen las primeras 16 letras del alfabeto latino, [A]..[P], el algoritmo inverso anterior podría visualizarse de la siguiente manera:

                   Original Input

1.                ABCDEFHGIJKLMNOP                   Recurse
2.        ABCDEFGH                IJKLMNOP           Recurse
3.    ABCD        EFGH        IJKL        MNOP       Recurse
4.  AB    CD    EF    GH    IJ    KL    MN    OP     Recurse

5. A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P    Terminate

6.  BA    DC    FE    HG    JI    LK    NM    PO     Reverse
7.    DCBA        HGFE        LKJI        PONM       Reverse
8.        HGFEDCBA                PONMLKJI           Reverse
9.                PONMLKJIHGFEDCBA                   Reverse

                  Reversed Output

Cualquier problema que se resuelve con un algoritmo recursivo sigue el Divide y vencerás paradigma, a saber que:

  1. El problema se divide en [dos o más] subproblemas donde cada subproblema es más pequeño que el problema original, pero se puede resolver de manera similar (Dividir).

  2. El problema se divide en [dos o más] subproblemas en los que cada subproblema es independiente y se puede resolver de forma recursiva o de manera sencilla si es lo suficientemente pequeño (Conquistar).

  3. El problema se divide en [dos o más] subproblemas donde los resultados de esos subproblemas se combinan para dar la solución al problema original (Combinar).

El pseudocódigo anterior para invertir una matriz cumple estrictamente los criterios anteriores. Por lo tanto, puede considerarse un algoritmo recursivo y podemos afirmar sin ninguna duda que la inversión de una matriz se puede hacer sin usar la iteración.


INFORMACIÓN DE ANTECEDENTES ADICIONAL
La diferencia entre iteración, implementaciones recursivas y algoritmos recursivos

Es un malentendido común que una implementación recursiva significa que un algoritmo es recursivo. No son equivalentes. Aquí hay una explicación definitiva de por qué, incluida una explicación detallada de la solución anterior.



¿Qué son la iteración y la recursividad?

En 1990, tres de los estudiosos más respetados del análisis de algoritmos modernos en el campo de la informática, Thomas H Cormen, Carlos E. Leiserson y Ronald L Rivest, lanzó su muy aclamado Introducción a los algoritmos. En este libro, que representó la unión de más de 200 textos respetados por derecho propio, y que durante más de 20 años se ha utilizado como el primer y único texto para enseñar algoritmos en la mayoría de las mejores universidades del mundo, Mssrs . Cormen, Leiserson y Rivest fueron explícitos acerca de lo que constituye Iterando y lo que constituye recurrente.

En su análisis y comparación de dos algoritmos de clasificación clásicos, Tipo de inserción y Ordenar fusión, explican las propiedades fundamentales de los algoritmos iterativos y recursivos (a veces denominados incrementales algoritmos para eliminar la ambigüedad cuando la noción matemática clásica de iteración se utiliza en el mismo contexto).

En primer lugar, la ordenación por inserción se clasifica como un algoritmo iterativo, cuyo comportamiento se resume de la siguiente manera:

Habiendo ordenado el subarreglo A[1..j-1], insertamos el elemento único A[j] en su lugar apropiado, produciendo la matriz ordenada A[1..j].

Fuente: Introducción a los algoritmos -Cormen, Leisersen, Rivest, 1990 MIT Press

Esta declaración clasifica un algoritmo iterativo como uno que se basa en el resultado o estado de una ejecución anterior ("iteración") del algoritmo, y que dichos resultados o información de estado se utilizan luego para resolver el problema de la iteración actual.

Merge Sort, por otro lado, se clasifica como un algoritmo recursivo. Un algoritmo recursivo se ajusta a un paradigma de procesamiento llamado Divide y vencerás el cual es un conjunto de tres criterios fundamentales que diferencian el funcionamiento de los algoritmos recursivos de los algoritmos no recursivos. Un algoritmo puede considerarse recursivo si, durante el procesamiento de un problema dado:

  1. El problema se divide en [dos o más] subproblemas donde cada subproblema es más pequeño que el problema original, pero se puede resolver de manera similar (Dividir).

  2. El problema se divide en [dos o más] subproblemas donde cada subproblema se puede resolver de forma recursiva o de manera directa si es lo suficientemente pequeño (Conquistar).

  3. El problema se divide en [dos o más] subproblemas donde los resultados de esos subproblemas se combinan para dar la solución al problema original (Combinar).

Referencia: Introducción a los algoritmos -Cormen, Leisersen, Rivest, 1990 MIT Press

Tanto los algoritmos iterativos como los algoritmos recursivos continúan su trabajo hasta que condición de terminación ha sido conseguido. La condición de terminación en la ordenación por inserción es que el jEl elemento 'th se ha colocado correctamente en la matriz A[1..j]. La condición de terminación en un algoritmo Divide y vencerás es cuando el Criterio 2 del paradigma "toca fondo", es decir, el tamaño de un subproblema alcanza un tamaño lo suficientemente pequeño como para que pueda resolverse sin más subdivisiones.

Es importante tener en cuenta que el paradigma Divide y vencerás requiere que los subproblemas se puedan resolver de manera similar al problema original para permitir la recurrencia. Como el problema original es un problema independiente, sin dependencias externas, se deduce que los subproblemas también deben poder resolverse como si fueran problemas independientes sin dependencias externas, particularmente en otros subproblemas. Esto significa que los subproblemas en los algoritmos Divide and Conquer deberían ser naturalmente apendiz más independiente.

Por el contrario, es igualmente importante tener en cuenta que la entrada a los algoritmos iterativos se basa en iteraciones anteriores del algoritmo, por lo que debe considerarse y procesarse en orden. Esto crea dependencias entre iteraciones que evitan que el algoritmo divida el problema en subproblemas que pueden resolverse recursivamente. En la ordenación por inserción, por ejemplo, no puede dividir los elementos A[1..j] en dos subconjuntos tales que la posición ordenada en la matriz de A[j] se decide antes que todos los elementos A[1..j-1] han sido colocados, como la posición propia real de A[j] puede moverse mientras cualquiera de A[1..j-1] se van colocando ellos mismos.

Algoritmos recursivos frente a implementaciones recursivas

El malentendido general del término recursividad proviene del hecho de que existe una suposición común y errónea de que un recurso recursivo implementación para alguna tarea automáticamente significa que el problema ha sido resuelto con un recurso recursivo algoritmo. recursivo algoritmos no son lo mismo que recursivo implementaciones y nunca lo ha sido.

Una implementación recursiva involucra una función, o grupo de funciones, que eventualmente se llaman a sí mismas para resolver una sub-porción de la tarea general exactamente de la misma manera en que se resuelve la tarea general. Sucede que recursiva algoritmos (es decir, aquellos que satisfacen el paradigma Divide y vencerás), se prestan bien a implementaciones recursivas. Sin embargo, los algoritmos recursivos se pueden implementar usando solo construcciones iterativas como for(...) y while(...) ya que todos los algoritmos, incluidos los algoritmos recursivos, terminan realizando alguna tarea repetidamente para obtener un resultado.

Otros colaboradores de esta publicación han demostrado perfectamente que los algoritmos iterativos se pueden implementar utilizando una función recursiva. De hecho, las implementaciones recursivas son posibles para todo eso implica iterar hasta que se cumpla alguna condición de terminación. Implementaciones recursivas donde no hay pasos Dividir o Combinar en el subyacente algoritmo son equivalentes a implementaciones iterativas con una condición de terminación estándar.

Tomando como ejemplo la ordenación por inserción, ya sabemos (y está probado) que la ordenación por inserción es un algoritmo iterativo. Sin embargo, esto no evita que una recursiva implementación de clasificación por inserción. De hecho, una implementación recursiva se puede crear muy fácilmente de la siguiente manera:

function insertionSort(array)

    if (length(array) == 1)
        return array
    end

    itemToSort = array[length(array)]
    array = insertionSort(array[1 .. (length(array)-1)])

    find position of itemToSort in array
    insert itemToSort into array

    return array

end

Como puede verse, la implementación es recursiva. Sin embargo, Insertion Sort es un algoritmo iterativo y esto lo sabemos. Entonces, ¿cómo sabemos que, incluso usando la implementación recursiva anterior, nuestro algoritmo Ordenar por inserción no se ha vuelto recursivo? Apliquemos los tres criterios del paradigma Divide y vencerás a nuestro algoritmo y comprobemos.

  1. El problema se divide en [dos o más] subproblemas donde cada subproblema es más pequeño que el problema original, pero se puede resolver de manera similar.

    Si: Excluyendo una matriz de longitud uno, el método para insertar un elemento A[j] en su lugar adecuado en la matriz es idéntico al método utilizado para insertar todos los elementos anteriores A[1..j-1] en la matriz.

  2. El problema se divide en [dos o más] subproblemas en los que cada subproblema es independiente y se puede resolver de forma recursiva o de manera sencilla si es lo suficientemente pequeño.

    NO: Colocación correcta del elemento A[j] es totalmente dependiente en la matriz que contiene A[1..j-1] elementos y los elementos que se están ordenando. Por lo tanto, el artículo A[j] (llamado elemento a ordenar) no se coloca en la matriz antes de que se procese el resto de la matriz.

  3. El problema se divide en [dos o más] subproblemas donde los resultados de esos subproblemas se combinan para dar la solución al problema original.

    NO: Al ser un algoritmo iterativo, solo un elemento A[j] se puede colocar correctamente en cualquier iteración dada. El espacio A[1..j] no se divide en subproblemas donde A[1], A[2]...A[j] se colocan correctamente de forma independiente y luego todos estos elementos colocados correctamente se combinan para dar la matriz ordenada.

Claramente, nuestra implementación recursiva no ha hecho que el algoritmo Ordenar por inserción sea de naturaleza recursiva. De hecho, la recursividad en la implementación en este caso está actuando como control de flujo, permitiendo que la iteración continúe hasta que se cumpla la condición final. Por lo tanto, usar una implementación recursiva no cambió nuestro algoritmo a un algoritmo recursivo.

Invertir una matriz sin utilizar un algoritmo iterativo

Entonces, ahora que entendemos qué hace que un algoritmo sea iterativo y recursivo, ¿cómo es que podemos invertir una matriz "sin usar la iteración"?

Hay dos formas de invertir una matriz. Ambos métodos requieren que conozca la longitud de la matriz de antemano. El algoritmo de iteración se ve favorecido por su eficiencia y su pseudocódigo tiene el siguiente aspecto:

function reverse(array)

    for each index i = 0 to (length(array) / 2 - 1)
        swap array[i] with array[length(array) - i]
    next

end

Este es un algoritmo puramente iterativo. Examinemos por qué podemos llegar a esta conclusión comparándola con el paradigma Divide y vencerás que determina el rendimiento de un algoritmo. recursividad.

  1. El problema se divide en [dos o más] subproblemas donde cada subproblema es más pequeño que el problema original, pero se puede resolver de manera similar.

    Si: La inversión de la matriz se desglosa en su granularidad más fina, los elementos y el procesamiento de cada elemento es idéntico al de todos los demás elementos procesados.

  2. El problema se divide en [dos o más] subproblemas en los que cada subproblema es independiente y se puede resolver de forma recursiva o de manera sencilla si es lo suficientemente pequeño.

    Si: Inversión de elemento i en la matriz es posible sin requerir ese elemento (yo + 1) (por ejemplo) se ha invertido o no. Además, la inversión del elemento i en la matriz no requiere los resultados de otras inversiones de elementos para poder completarse.

  3. El problema se divide en [dos o más] subproblemas donde los resultados de esos subproblemas se combinan para dar la solución al problema original.

    NO: Al ser un algoritmo iterativo, solo se realiza una etapa de cálculo en cada paso del algoritmo. No divide los problemas en subproblemas y no se combinan los resultados de dos o más subproblemas para obtener un resultado.

El análisis anterior de nuestro primer algoritmo anterior confirmó que no se ajusta al paradigma Divide and Conquer y, por lo tanto, no puede considerarse un algoritmo recursivo. Sin embargo, como se cumplieron los criterios (1) y (2), es evidente que podría ser posible un algoritmo recursivo.

La clave radica en el hecho de que los subproblemas en nuestra solución iterativa son de la menor granularidad posible (es decir, elementos). Al dividir el problema en subproblemas cada vez más pequeños (en lugar de optar por la granularidad más fina desde el principio) y luego fusionar los resultados de los subproblemas, el algoritmo puede volverse recursivo.

Por ejemplo, si tenemos una matriz de 16 elementos que contienen las primeras 16 letras del alfabeto latino (A..P), un algoritmo recursivo se vería visualmente de la siguiente manera:

                   Original Input

1.                ABCDEFHGIJKLMNOP                   Divide
2.        ABCDEFGH                IJKLMNOP           Divide
3.    ABCD        EFGH        IJKL        MNOP       Divide
4.  AB    CD    EF    GH    IJ    KL    MN    OP     Divide

5. A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P    Terminate

6.  BA    DC    FE    HG    JI    LK    NM    PO     Conquer (Reverse) and Merge
7.    DCBA        HGFE        LKJI        PONM       Conquer (Reverse) and Merge
8.        HGFEDCBA                PONMLKJI           Conquer (Reverse) and Merge
9.                PONMLKJIHGFEDCBA                   Conquer (Reverse) and Merge

                  Reversed Output

Desde el nivel superior, los 16 elementos se dividen progresivamente en tamaños de subproblema más pequeños de exactamente el mismo tamaño (niveles 1 a 4) hasta que alcanzamos la granularidad más fina del subproblema; arreglos de longitud unitaria en orden hacia adelante (paso 5, elementos individuales). En este punto, nuestros 16 elementos de matriz todavía parecen estar en orden. Sin embargo, al mismo tiempo también están invertidos, ya que una matriz de un solo elemento también es una matriz invertida por derecho propio. Los resultados de las matrices de un solo elemento se fusionan para obtener ocho matrices invertidas de longitud dos (paso 6), luego se fusionan nuevamente para obtener cuatro matrices invertidas de longitud cuatro (paso 7), y así sucesivamente hasta que se reconstruye nuestra matriz original. en reversa (pasos 6 a 9).

El pseudocódigo del algoritmo recursivo para invertir una matriz tiene el siguiente aspecto:

function reverse(array)

    /* check terminating condition. all single elements are also reversed
     * arrays of unit length.
     */
    if (length(array) < 2) then
        return array

    /* divide problem in two equal sub-problems. we process the sub-problems
     * in reverse order so that when combined the array has been reversed.
     */
    return reverse(array[(n/2) .. (n-1)]) + reverse(array[0 .. ((n/2)-1)])

end

Como puede ver, el algoritmo divide el problema en subproblemas hasta que alcanza la granularidad más fina del subproblema que da un resultado instantáneo. Luego invierte los resultados mientras se fusionan para dar una matriz de resultados invertida. Aunque pensamos que este algoritmo es recursivo, apliquemos los tres criterios para los algoritmos Divide and Conquer para confirmar.

  1. El problema se divide en [dos o más] subproblemas donde cada subproblema es más pequeño que el problema original, pero se puede resolver de manera similar.

    Si: La inversión de la matriz en el nivel uno se puede realizar utilizando exactamente el mismo algoritmo que en los niveles 2, 3, 4 o cinco.

  2. El problema se divide en [dos o más] subproblemas en los que cada subproblema es independiente y se puede resolver de forma recursiva o de manera sencilla si es lo suficientemente pequeño.

    Si: Cada subproblema que no es de longitud unitaria se resuelve dividiendo el problema en dos subarreglos independientes e invirtiendo recursivamente esos subarreglos. Los arreglos de longitud unitaria, los arreglos más pequeños posibles, se invierten ellos mismos para proporcionar una condición de terminación y un primer conjunto garantizado de resultados combinados.

  3. El problema se divide en [dos o más] subproblemas donde los resultados de esos subproblemas se combinan para dar la solución al problema original.

    Si: Todos los problemas de los niveles 6, 7, 8 y 9 se componen únicamente de resultados del nivel inmediatamente superior; es decir, de sus subproblemas. La inversión de la matriz en cada nivel da como resultado un resultado general invertido.

Como puede verse, nuestro algoritmo recursivo superó los tres criterios del paradigma Divide y vencerás, por lo que puede considerarse un algoritmo verdaderamente recursivo. Por lo tanto es posible invertir una matriz sin utilizar un algoritmo iterativo.

Es interesante notar que nuestro algoritmo iterativo original para la inversión de arreglos puede ser implementado utilizando una función recursiva. El pseudocódigo para tal implementación es el siguiente:

function reverse(array)

    if length(array) < 2
        return
    end

    swap array[0] and array[n-1]
    reverse(array[1..(n-1)])

end

Esto es similar a las soluciones propuestas por otros carteles. esto es recursivo implementación ya que la función definida finalmente se llama a sí misma para realizar repetidamente la misma tarea en todos los elementos de la matriz. Sin embargo, esto hace no hacer el algoritmo recursivo, ya que no hay división de los problemas en subproblemas, y no hay fusión de los resultados de los subproblemas para dar el resultado final. En este caso, la recursividad simplemente se usa como una construcción de control de flujo y, algorítmicamente, se puede demostrar que el resultado general realiza la misma secuencia de pasos, exactamente en el mismo orden, que el algoritmo iterativo original que se propuso para el solución.

Esa es la diferencia entre un Algoritmo iterativo, Algoritmo recursivo, Y un Implementación recursiva.

Respondido 07 Jul 12, 06:07

Realmente tipo ¡¿esta?! - Shahbaz

La solución inicial la supe al instante; es un uso de libro de texto de la recursividad. El trasfondo de esto tardó unos días en escribirse. Lo que es más importante, el póster original potencialmente ha sido mal informado y aceptó la respuesta incorrecta. Eso es lo que quería arreglar. - aps2012

@ aps2012 Creo que te referías al alfabeto latino, ya que ahora solo se usan números romanos: Subsecuente

-1 a pesar del buen algoritmo recursivo porque su distinción entre "algoritmos" recursivos e "implementaciones" es completamente imaginaria. Un algoritmo iterativo es simplemente un algoritmo recursivo en el que uno de los subproblemas es siempre un caso base: algoritmos iterativos \subconjunto de algoritmos recursivos. Déjame aclarar tu confusión sobre el ordenamiento por inserción: tenemos IS(x:rest) = merge(IS(x), IS(rest)), con IS(x) = x. La fusión del elemento x en el resto de la lista es no es diferente de ¡la fusión que hace mergesort después de dividir el problema en dos! - j_random_hacker

@RayToal: Gracias, aprecio sus esfuerzos por ser diplomático y estoy de acuerdo en que hay espacio para el debate sobre qué significa exactamente la recursividad (por ejemplo, ¿sigue siendo "recursividad" si una función recursiva de cola se compila en un ciclo iterativo?), pero debo insistir en que la taxonomía de aps2012 es objetivamente incorrecta (se olvidó de combinar los subproblemas resueltos) y confusa. Con la cantidad de votos a favor que tiene (supongo que en base a la extensión de la publicación y la mención de Cormen et al.), ¡está engañando a muchas personas! - j_random_hacker

Como la gente ha dicho en los comentarios, depende de la definición de iteración.

Caso 1. La iteración como estilo de programación, diferente a la recursividad

Si uno toma la recursividad (simplemente) como un alternativa a la iteración, entonces la solución recursiva presentada por Kalai es la respuesta correcta.

Caso 2. Iteración como límite inferior de tiempo lineal

Si uno toma la iteración como "examinar cada elemento", entonces la pregunta se convierte en si la inversión de la matriz requiere un tiempo lineal o se puede hacer en un tiempo sublineal.

Para mostrar que no existe un algoritmo sublineal para la inversión de arreglos, considere un arreglo con n elementos. Suponga un algoritmo A existe para la inversión que no necesita leer cada elemento. Entonces existe un elemento a[i] para algunos i in 0..n-1 que el algoritmo nunca lee, pero aún puede invertir correctamente la matriz. (EDITAR: debemos excluir el elemento central de una matriz de longitud impar (consulte los comentarios a continuación de este rango), consulte los comentarios a continuación, pero esto no afecta si el algoritmo es lineal o sublineal en el caso asintótico).

Dado que el algoritmo nunca lee el elemento a[i] podemos cambiar su valor. Digamos que hacemos esto. Luego, el algoritmo, al no haber leído nunca este valor, producirá la misma respuesta para la inversión que antes de que cambiáramos su valor. Pero esta respuesta no será correcta para el nuevo valor de a[i]. Por lo tanto, no existe un algoritmo de inversión correcto que no lea al menos cada elemento de matriz de entrada (salvo uno). Por lo tanto, la inversión de matriz tiene un límite inferior de O (n) y, por lo tanto, requiere iteración (según la definición de trabajo para este escenario).

(Tenga en cuenta que esta prueba es solo para la inversión de matrices y no se extiende a los algoritmos que realmente tienen implementaciones sublineales, como la búsqueda binaria y la búsqueda de elementos).

Caso 3. Iteración como construcción de bucle

Si la iteración se toma como "bucle hasta que se cumpla una condición", entonces esto se traduce en un código de máquina con saltos condicionales, que se sabe que requiere una optimización seria del compilador (aprovechando la predicción de bifurcación, etc.). En este caso, alguien que pregunta si hay un manera de hacer algo "sin iteración" puede tener en mente desenrollar el bucle (al código de línea recta). En este caso, en principio, puede escribir código C de línea recta (sin bucles). Pero esta técnica no es general; solo funciona si conoce el tamaño de la matriz de antemano. (Perdón por agregar este caso más o menos frívolo a la respuesta, pero lo hice para completar y porque escuché el término "iteración" usado de esta manera, y el desenrollado de bucles es una importante optimización del compilador).

Respondido el 20 de junio de 20 a las 10:06

" Pero esta respuesta no será correcta para el nuevo valor de a[i]. " incorrecta. esto no es clasificación inversa. la inversión es independiente de los valores almacenados. En cualquier matriz de longitud impar, no necesita leer el elemento central en absoluto. - Will Ness

@WillNess: el elemento en el medio de una matriz de longitud impar es el , solamente elemento que puede evitar leer con seguridad. IOW puede omitir la lectura de solo O (1) de O (n) elementos. La prueba de Ray sería mejor si abordara este caso de la esquina (y si dijera "Pero siempre podemos elegir un valor para a[i] tal que esta respuesta no será correcta para el nuevo valor de a[i]") pero su razonamiento y el límite inferior de O(n) son fundamentalmente sólidos. - j_random_hacker

@j_random_hacker No lo sigo. la inversión es independiente de los valores almacenados. Imagine que los valores almacenados son estructuras complejas y las celdas de matriz contienen punteros a estos valores; entonces la inversión no tiene que leer ningún valor ni una sola vez, solo intercambia punteros almacenados en celdas. Y, de hecho, la Q se relaciona con la implementación de la matriz. Puede implementar una matriz de manera que la inversión tome O (1) tiempo, fácilmente. Simplemente coloque un adaptador de direccionamiento encima. - Will Ness

@WillNess: incluso si los elementos de la matriz son estructuras complejas, los punteros O (n) - 1 = O (n) deberán intercambiarse => O (n) trabajo. La construcción de un adaptador de inversión suele ser una buena idea, ya que permitirá búsquedas O(1), pero eso se sale de la definición del problema; del mismo modo, puede crear una vista rotada de una matriz con un adaptador que usa un desplazamiento, pero eso es no es lo mismo que rotar sus elementos :) - j_random_hacker

@WillNess: Para ser lo más claro posible: para esta pregunta, se especifica a priori una función A[i] que devuelve el valor en la posición i en la matriz A; se nos pide que reorganicemos A para que termine al revés con respecto a esta función. Para los propósitos de esta pregunta, no se nos permite construir una nueva función A'[i] tal que la matriz se invierta. - j_random_hacker

Usa la función recursiva.

void reverse(int a[],int start,int end)
{
     int temp;
     temp = a[start];
     a[start] = a[end];
     a[end] = temp;


    if(start==end ||start==end-1)
       return;
    reverse(a, start+1, end-1);
}

Simplemente llame al método anterior como inversa (matriz, 0, longitud de matriz-1)

Respondido 07 Feb 13, 10:02

La recursividad es una iteración disfrazada. Al final, la CPU accede a la memoria de forma iterativa de todos modos. Sólo con gastos generales inútiles. - Ondra Zižka

@aps2012, esto is un algoritmo recursivo: es esencialmente lo mismo que rev(a) = (a[n]) + rev(a[2..n-1]) + (a[1]) (con las condiciones de parada adecuadas). - huón

@ aps2012, discutir sobre definiciones no tiene sentido (y esto es lo que es), pero el uso común sugiere que esta respuesta es recursiva: a excepción de su respuesta, todos las el Definiciones of recursividad, incluyendo algoritmos recursivos He visto que no se limitan sólo a divide y vencerás. - huón

(Además, su declaración pasivo-agresiva "comparta su sabiduría, en detalle como yo la tengo" es innecesaria, por favor absténgase de hacer eso en el futuro; algo como "Si pudiera explicarse más, se lo agradecería" sería mucho mejor). - huón

@ aps2012, hice una copia de seguridad de mi vista: esta respuesta satisface la definición convencional de "algoritmo recursivo". ¿No leíste los 4 enlaces que proporcioné? (De todos modos, odio discutir con la autoridad pero: he estado aquí más tiempo que tú (y tengo más "reputación" y una reputación promedio más alta por respuesta), así que probablemente entiendo la dinámica de SO un poco mejor. :)) - huón

Implemente una función recursiva para invertir una matriz ordenada. Es decir, dada la matriz [1, 2, 3, 4, 5], su procedimiento debería devolver [5, 4, 3, 2, 1].

Respondido 29 Jul 13, 15:07

No hay razón para agregar una respuesta a una pregunta ya respondida. Esto no agrega ningún valor aquí y tampoco obtendrá ningún voto positivo a menos que el suyo sea diferente a las respuestas ya establecidas. Pruebe su suerte en las preguntas sin ninguna respuesta aceptada. - Aseem Bansal

Aquí hay una solución ordenada que usa la recursividad en una función de javascript. No requiere ningún parámetro más que la propia matriz.

/* Use recursion to reverse an array */
function reverse(a){
    if(a.length==undefined || a.length<2){
        return a;
    }
    b=[];
    b.push(reverse(copyChop(a)));
    b.push(a[0]);
    return b;
    /* Return a copy of an array minus the first element */
    function copyChop(a){ 
        b=a.slice(1); 
        return b;
    }
}

Llámalo de la siguiente manera;

reverse([1,2,3,4]);

Tenga en cuenta que si no usa la función anidada copyChop para hacer el corte de la matriz, terminará con una matriz como el primer elemento en su resultado final. No estoy muy seguro de por qué esto debería ser así

Respondido el 30 de junio de 13 a las 08:06

Esta pregunta está etiquetada como C, entonces, ¿por qué están dando una solución de Javascript? - Aseem Bansal

   #include<stdio.h>


   void rev(int *a,int i,int n)
  {

if(i<n/2)
{
    int temp = a[i];
    a[i]=a[n-i-1];
    a[n-i-1]=temp;
    rev(a,++i,n);
 }
}
int main()
    {
    int array[] = {3,2,4,5,6,7,8};
   int len = (sizeof(array)/sizeof(int));
   rev(array,0,len);    
   for(int i=0;i<len;i++)
   {
    printf("\n array[%d]->%d",i,array[i]);
  }
}

respondido 13 mar '14, 02:03

Una solución podría ser:

#include <stdio.h>
#include <stdlib.h>

void swap(int v[], int v_start, int v_middle, int v_end) {
    int *aux = calloc(v_middle - v_start, sizeof(int));
    
    int k = 0;
    for(int i = v_start; i <= v_middle; i++) {
        aux[k] = v[i];
        k = k + 1;
    }

    k = v_start;
    for(int i = v_middle + 1; i <= v_end; i++) {
        v[k] = v[i];
        k = k + 1;
    }

    for(int i = 0; i <= v_middle - v_start; i++) {
        v[k] = aux[i];
        k = k + 1;
    }
}

void divide(int v[], int v_start, int v_end) {
    if(v_start < v_end) {
        int v_middle = (v_start + v_start)/2;
        divide(v, v_start, v_middle);
        divide(v, v_middle + 1, v_end);
        swap(v, v_start, v_middle, v_end);
    }
}

int main() {
    int v[10] = {4, 20, 12, 100, 50, 9}, n = 6;
    
    printf("Array: \n");
    for (int i = 0; i < n; i++) {
        printf("%d ", v[i]);
    }
    printf("\n\n");

    divide(v, 0, n - 1);

    printf("Reversed: \n");
    for (int i = 0; i < n; i++) {
        printf("%d ", v[i]);
    }

    return 0;
}

Respondido 13 Feb 22, 19:02

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.