Come si fa a ruotare un array bidimensionale?


302

Ispirato al post di Raymond Chen , supponi di avere un array bidimensionale 4x4, scrivi una funzione che lo ruota di 90 gradi. Raymond si collega a una soluzione in pseudo codice, ma mi piacerebbe vedere alcune cose del mondo reale.

[1][2][3][4]
[5][6][7][8]
[9][0][1][2]
[3][4][5][6]

diventa:

[3][9][5][1]
[4][0][6][2]
[5][1][7][3]
[6][2][8][4]

Aggiornamento : la risposta di Nick è la più semplice, ma c'è un modo per farlo meglio di n ^ 2? E se la matrice fosse 10000x10000?


99
Come hai potuto cavartela con meno di n ^ 2? Tutti gli elementi devono essere letti e impostati e ci sono n ^ 2 elementi
erikkallen


9
Qual è la tua n? Non dici se l'array 2D è quadrato (non è nel caso generale! Ad esempio un vettore è una matrice con una dimensione di 1), ma sembra che tu implichi che n è la larghezza e l'altezza, e quindi hanno n² elementi . Avrebbe più senso avere n il numero di elementi, con n = w × h.
niXar,

1
Ecco un modo rapido per farlo: memorizzare gli indici di riga e colonna (diciamo i e j). La trasposizione richiede tempo costante (basta scambiare gli indici :). Puoi fare lo stesso con le rotazioni (gioca con gli indici).
Saadtaame,

4
Nel caso in cui n ^ 2 non sia fattibile. È possibile creare un'interfaccia che acceda a ciascun elemento. Quindi, dato (i, j), applica la rotazione per (i, j) per accedere all'elemento ruotato e tornare. Potrebbe non essere il miglior soln ma funziona.
Confondere l'

Risposte:


140

Eccolo in C #

int[,] array = new int[4,4] {
    { 1,2,3,4 },
    { 5,6,7,8 },
    { 9,0,1,2 },
    { 3,4,5,6 }
};

int[,] rotated = RotateMatrix(array, 4);

static int[,] RotateMatrix(int[,] matrix, int n) {
    int[,] ret = new int[n, n];

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            ret[i, j] = matrix[n - j - 1, i];
        }
    }

    return ret;
}

6
Certo, ma che dire di una soluzione che utilizza la memoria O (1)?
AlexeyMK,

20
La tua soluzione ha O (n ^ 2) complessità spaziale. Devo fare di meglio
Kshitij Jain,

6
Che ne dici della matrice NXM?
Rohit

18
La complessità è lineare nel numero di elementi nell'array. Se N è il numero di elementi, la complessità è O (N). Se N è la lunghezza del lato, quindi sì, la complessità è O (N ^ 2), ma è comunque ottimale. Devi leggere ogni elemento almeno una volta. Stampare la matrice è la stessa complessità
Alejandro il

6
Per una rotazione di -90 gradi:ret[i][j] = matrix[j][n - i - 1]
Duncan Luk

387

Algoritmo O (n ^ 2) tempo e O (1) spazio (senza soluzioni alternative e roba ficcanaso!)

Ruota di +90:

  1. Trasporre
  2. Invertire ogni riga

Ruota di -90:

Metodo 1:

  1. Trasporre
  2. Invertire ogni colonna

Metodo 2:

  1. Invertire ogni riga
  2. Trasporre

Ruota di +180:

Metodo 1 : ruota di +90 due volte

Metodo 2 : Invertire ciascuna riga e quindi invertire ciascuna colonna (Trasposizione)

Ruota di -180:

Metodo 1 : ruotare di -90 due volte

Metodo 2 : Invertire ogni colonna e quindi invertire ogni riga

Metodo 3 : ruota di +180 poiché sono uguali


4
Questo è stato molto utile per me; Sono stato in grado di scrivere un algoritmo una volta che ho conosciuto la "versione [pseudo-] codice" di questa operazione. Grazie!
duma,

13
Una delle mie risposte SO preferite di tutti i tempi. Molto istruttivo!
g33kz0r

2
Ecco un'implementazione JavaScript JSFiddle se qualcuno è interessato.
Mr. Polywhirl,

6
Ruota di -90: (1) Inverti ogni riga; (2) Trasporre. Haskell: rotateCW = map reverse . transposeerotateCCW = transpose . map reverse
Thomas Eding,

5
Qual è la differenza tra la rotazione di 180 e -180?
Qian Chen,

178

Vorrei aggiungere qualche dettaglio in più. In questa risposta, i concetti chiave si ripetono, il ritmo è lento e intenzionalmente ripetitivo. La soluzione fornita qui non è la più sintatticamente compatta, ma è destinata a coloro che desiderano apprendere cos'è la rotazione della matrice e l'implementazione risultante.

Innanzitutto, cos'è una matrice? Ai fini di questa risposta, una matrice è solo una griglia in cui larghezza e altezza sono uguali. Nota, la larghezza e l'altezza di una matrice possono essere diverse, ma per semplicità, questo tutorial considera solo le matrici con uguale larghezza e altezza ( matrici quadrate ). E sì, matrici sono il plurale di matrice.

Le matrici di esempio sono: 2 × 2, 3 × 3 o 5 × 5. O, più in generale, N × N. Una matrice 2 × 2 avrà 4 quadrati perché 2 × 2 = 4. Una matrice 5 × 5 avrà 25 quadrati perché 5 × 5 = 25. Ogni quadrato è chiamato elemento o voce. Rappresenteremo ogni elemento con un punto ( .) nei diagrammi seguenti:

Matrice 2 × 2

. .
. .

Matrice 3 × 3

. . .
. . .
. . .

Matrice 4 × 4

. . . .
. . . .
. . . .
. . . .

Quindi, cosa significa ruotare una matrice? Prendiamo una matrice 2 × 2 e mettiamo alcuni numeri in ciascun elemento in modo da poter osservare la rotazione:

0 1
2 3

Ruotandolo di 90 gradi ci dà:

2 0
3 1

Abbiamo letteralmente girato l'intera matrice una volta verso destra, proprio come girare il volante di un'auto. Può essere utile pensare di "inclinare" la matrice sul lato destro. Vogliamo scrivere una funzione, in Python, che prende una matrice e ruota una volta verso destra. La firma della funzione sarà:

def rotate(matrix):
    # Algorithm goes here.

La matrice verrà definita utilizzando una matrice bidimensionale:

matrix = [
    [0,1],
    [2,3]
]

Pertanto la prima posizione dell'indice accede alla riga. La seconda posizione dell'indice accede alla colonna:

matrix[row][column]

Definiremo una funzione di utilità per stampare una matrice.

def print_matrix(matrix):
    for row in matrix:
        print row

Un metodo per ruotare una matrice è quello di farlo uno strato alla volta. Ma cos'è uno strato? Pensa a una cipolla. Proprio come gli strati di una cipolla, mentre ogni strato viene rimosso, ci spostiamo verso il centro. Altre analogie sono una bambola Matryoshka o un gioco di pacchi.

La larghezza e l'altezza di una matrice determinano il numero di strati in quella matrice. Usiamo simboli diversi per ogni livello:

Una matrice 2 × 2 ha 1 strato

. .
. .

Una matrice 3 × 3 ha 2 strati

. . .
. x .
. . .

Una matrice 4 × 4 ha 2 strati

. . . .
. x x .
. x x .
. . . .

Una matrice 5 × 5 ha 3 strati

. . . . .
. x x x .
. x O x .
. x x x .
. . . . .

Una matrice 6 × 6 ha 3 strati

. . . . . .
. x x x x .
. x O O x .
. x O O x .
. x x x x .
. . . . . .

Una matrice 7 × 7 ha 4 strati

. . . . . . .
. x x x x x .
. x O O O x .
. x O - O x .
. x O O O x .
. x x x x x .
. . . . . . .

Si può notare che l'incremento della larghezza e dell'altezza di una matrice di uno non aumenta sempre il numero di livelli. Prendendo le matrici sopra e tabulando i livelli e le dimensioni, vediamo il numero di livelli aumentare una volta ogni due incrementi di larghezza e altezza:

+-----+--------+
| N×N | Layers |
+-----+--------+
| 1×1 |      1 |
| 2×2 |      1 |
| 3×3 |      2 |
| 4×4 |      2 |
| 5×5 |      3 |
| 6×6 |      3 |
| 7×7 |      4 |
+-----+--------+

Tuttavia, non tutti gli strati devono essere ruotati. Una matrice 1 × 1 è la stessa prima e dopo la rotazione. Lo strato centrale 1 × 1 è sempre lo stesso prima e dopo la rotazione, indipendentemente dalla dimensione complessiva della matrice:

+-----+--------+------------------+
| N×N | Layers | Rotatable Layers |
+-----+--------+------------------+
| 1×1 |      1 |                0 |
| 2×2 |      1 |                1 |
| 3×3 |      2 |                1 |
| 4×4 |      2 |                2 |
| 5×5 |      3 |                2 |
| 6×6 |      3 |                3 |
| 7×7 |      4 |                3 |
+-----+--------+------------------+

Data la matrice N × N, come possiamo determinare a livello di codice il numero di strati che dobbiamo ruotare? Se dividiamo la larghezza o l'altezza per due e ignoriamo il resto otteniamo i seguenti risultati.

+-----+--------+------------------+---------+
| N×N | Layers | Rotatable Layers |   N/2   |
+-----+--------+------------------+---------+
| 1×1 |      1 |                0 | 1/2 = 0 |
| 2×2 |      1 |                1 | 2/2 = 1 |
| 3×3 |      2 |                1 | 3/2 = 1 |
| 4×4 |      2 |                2 | 4/2 = 2 |
| 5×5 |      3 |                2 | 5/2 = 2 |
| 6×6 |      3 |                3 | 6/2 = 3 |
| 7×7 |      4 |                3 | 7/2 = 3 |
+-----+--------+------------------+---------+

Notare come N/2 corrisponde il numero di livelli che devono essere ruotati? A volte il numero di strati ruotabili è uno in meno del numero totale di strati nella matrice. Ciò si verifica quando lo strato più interno è formato da un solo elemento (cioè una matrice 1 × 1) e pertanto non è necessario ruotarlo. Viene semplicemente ignorato.

Indubbiamente avremo bisogno di queste informazioni nella nostra funzione per ruotare una matrice, quindi aggiungiamole ora:

def rotate(matrix):
    size = len(matrix)
    # Rotatable layers only.
    layer_count = size / 2

Ora sappiamo quali sono i layer e come determinare il numero di layer che devono effettivamente essere ruotati, come isoliamo un singolo layer in modo da poterlo ruotare? Innanzitutto, ispezioniamo una matrice dallo strato più esterno, verso l'interno, allo strato più interno. Una matrice 5 × 5 ha tre strati in totale e due strati che devono essere ruotati:

. . . . .
. x x x .
. x O x .
. x x x .
. . . . .

Diamo un'occhiata alle colonne per prime. La posizione delle colonne che definiscono il livello più esterno, supponendo che contiamo da 0, sono 0 e 4:

+--------+-----------+
| Column | 0 1 2 3 4 |
+--------+-----------+
|        | . . . . . |
|        | . x x x . |
|        | . x O x . |
|        | . x x x . |
|        | . . . . . |
+--------+-----------+

0 e 4 sono anche le posizioni delle righe per il livello più esterno.

+-----+-----------+
| Row |           |
+-----+-----------+
|   0 | . . . . . |
|   1 | . x x x . |
|   2 | . x O x . |
|   3 | . x x x . |
|   4 | . . . . . |
+-----+-----------+

Questo sarà sempre il caso poiché la larghezza e l'altezza sono uguali. Pertanto possiamo definire le posizioni di colonna e riga di un livello con solo due valori (anziché quattro).

Spostandosi verso l'interno verso il secondo livello, la posizione delle colonne è 1 e 3. E, sì, hai indovinato, è lo stesso per le righe. È importante capire che abbiamo dovuto sia aumentare che diminuire le posizioni di riga e colonna quando ci si sposta verso l'interno al livello successivo.

+-----------+---------+---------+---------+
|   Layer   |  Rows   | Columns | Rotate? |
+-----------+---------+---------+---------+
| Outermost | 0 and 4 | 0 and 4 | Yes     |
| Inner     | 1 and 3 | 1 and 3 | Yes     |
| Innermost | 2       | 2       | No      |
+-----------+---------+---------+---------+

Quindi, per ispezionare ogni livello, vogliamo un loop con contatori sia in aumento che in diminuzione che rappresentano lo spostamento verso l'interno, a partire dal livello più esterno. Lo chiameremo il nostro "loop di layer".

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2

    for layer in range(0, layer_count):
        first = layer
        last = size - first - 1
        print 'Layer %d: first: %d, last: %d' % (layer, first, last)

# 5x5 matrix
matrix = [
    [ 0, 1, 2, 3, 4],
    [ 5, 6, 6, 8, 9],
    [10,11,12,13,14],
    [15,16,17,18,19],
    [20,21,22,23,24]
]

rotate(matrix)

Il codice sopra scorre attraverso le posizioni (riga e colonna) di tutti i livelli che devono essere ruotati.

Layer 0: first: 0, last: 4
Layer 1: first: 1, last: 3

Ora abbiamo un loop che fornisce le posizioni delle righe e delle colonne di ogni livello. Le variabili firste lastidentificano la posizione dell'indice della prima e dell'ultima riga e colonna. Facendo riferimento alle nostre tabelle di righe e colonne:

+--------+-----------+
| Column | 0 1 2 3 4 |
+--------+-----------+
|        | . . . . . |
|        | . x x x . |
|        | . x O x . |
|        | . x x x . |
|        | . . . . . |
+--------+-----------+

+-----+-----------+
| Row |           |
+-----+-----------+
|   0 | . . . . . |
|   1 | . x x x . |
|   2 | . x O x . |
|   3 | . x x x . |
|   4 | . . . . . |
+-----+-----------+

Quindi possiamo navigare attraverso i livelli di una matrice. Ora abbiamo bisogno di un modo per navigare all'interno di un livello in modo da poter spostare elementi attorno a quel livello. Nota, gli elementi non saltano mai da un livello all'altro, ma si muovono all'interno dei rispettivi livelli.

Ruotando ciascun elemento in un livello si ruota l'intero livello. Ruotando tutti i livelli in una matrice si ruota l'intera matrice. Questa frase è molto importante, quindi fai del tuo meglio per capirla prima di andare avanti.

Ora, abbiamo bisogno di un modo per spostare effettivamente gli elementi, cioè ruotare ciascun elemento, e successivamente il livello, e infine la matrice. Per semplicità, torneremo a una matrice 3x3 - che ha uno strato ruotabile.

0 1 2
3 4 5
6 7 8

Il nostro loop di livelli fornisce gli indici della prima e dell'ultima colonna, nonché della prima e dell'ultima riga:

+-----+-------+
| Col | 0 1 2 |
+-----+-------+
|     | 0 1 2 |
|     | 3 4 5 |
|     | 6 7 8 |
+-----+-------+

+-----+-------+
| Row |       |
+-----+-------+
|   0 | 0 1 2 |
|   1 | 3 4 5 |
|   2 | 6 7 8 |
+-----+-------+

Poiché le nostre matrici sono sempre quadrate, abbiamo bisogno solo di due variabili firste last, poiché le posizioni dell'indice sono le stesse per righe e colonne.

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2

    # Our layer loop i=0, i=1, i=2
    for layer in range(0, layer_count):

        first = layer
        last = size - first - 1

        # We want to move within a layer here.

Le variabili prima e ultima possono essere facilmente utilizzate per fare riferimento ai quattro angoli di una matrice. Questo perché gli angoli stessi possono essere definiti usando varie permutazioni di firste last(senza sottrazione, aggiunta o offset di tali variabili):

+---------------+-------------------+-------------+
| Corner        | Position          | 3x3 Values  |
+---------------+-------------------+-------------+
| top left      | (first, first)    | (0,0)       |
| top right     | (first, last)     | (0,2)       |
| bottom right  | (last, last)      | (2,2)       |
| bottom left   | (last, first)     | (2,0)       |
+---------------+-------------------+-------------+

Per questo motivo, iniziamo la nostra rotazione dai quattro angoli esterni: li ruoteremo per primi. Evidenziamoli con *.

* 1 *
3 4 5
* 7 *

Vogliamo scambiare ciascuno *con il *a destra di esso. Quindi andiamo avanti con una stampa dei nostri angoli definiti usando solo varie permutazioni di firste last:

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2
    for layer in range(0, layer_count):

        first = layer
        last = size - first - 1

        top_left = (first, first)
        top_right = (first, last)
        bottom_right = (last, last)
        bottom_left = (last, first)

        print 'top_left: %s' % (top_left)
        print 'top_right: %s' % (top_right)
        print 'bottom_right: %s' % (bottom_right)
        print 'bottom_left: %s' % (bottom_left)

matrix = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
]

rotate(matrix)

L'output dovrebbe essere:

top_left: (0, 0)
top_right: (0, 2)
bottom_right: (2, 2)
bottom_left: (2, 0)

Ora possiamo scambiare abbastanza facilmente ciascuno degli angoli all'interno del nostro loop di livelli:

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2
    for layer in range(0, layer_count):

        first = layer
        last = size - first - 1

        top_left = matrix[first][first]
        top_right = matrix[first][last]
        bottom_right = matrix[last][last]
        bottom_left = matrix[last][first]

        # bottom_left -> top_left
        matrix[first][first] = bottom_left
        # top_left -> top_right
        matrix[first][last] = top_left
        # top_right -> bottom_right
        matrix[last][last] = top_right
        # bottom_right -> bottom_left
        matrix[last][first] = bottom_right


print_matrix(matrix)
print '---------'
rotate(matrix)
print_matrix(matrix)

Matrice prima di ruotare gli angoli:

[0, 1, 2]
[3, 4, 5]
[6, 7, 8]

Matrice dopo aver ruotato gli angoli:

[6, 1, 0]
[3, 4, 5]
[8, 7, 2]

Grande! Abbiamo ruotato con successo ogni angolo della matrice. Ma non abbiamo ruotato gli elementi nel mezzo di ogni livello. Chiaramente abbiamo bisogno di un modo per scorrere all'interno di un livello.

Il problema è che l'unico loop nella nostra funzione finora (il nostro loop di layer) si sposta al layer successivo su ogni iterazione. Poiché la nostra matrice ha un solo strato ruotabile, l'anello di livello esce dopo aver ruotato solo gli angoli. Diamo un'occhiata a ciò che accade con una matrice più grande, 5 × 5 (in cui due strati devono essere ruotati). Il codice funzione è stato omesso, ma rimane lo stesso di sopra:

matrix = [
[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]
]
print_matrix(matrix)
print '--------------------'
rotate(matrix)
print_matrix(matrix)

L'output è:

[20,  1,  2,  3,  0]
[ 5, 16,  7,  6,  9]
[10, 11, 12, 13, 14]
[15, 18, 17,  8, 19]
[24, 21, 22, 23,  4]

Non dovrebbe sorprendere che gli angoli del livello più esterno siano stati ruotati, ma potresti anche notare che sono stati ruotati anche gli angoli del livello successivo (verso l'interno). Questo ha senso. Abbiamo scritto codice per navigare tra i livelli e anche per ruotare gli angoli di ciascun livello. Sembra un progresso, ma sfortunatamente dobbiamo fare un passo indietro. Passare al livello successivo non è affatto utile fino a quando il livello precedente (esterno) non viene completamente ruotato. Cioè, fino a quando ogni elemento nel livello è stato ruotato. Ruotare solo gli angoli non lo farà!

Fai un respiro profondo. Abbiamo bisogno di un altro ciclo. Un ciclo nidificato non meno. Il nuovo ciclo nidificato utilizzerà le variabili firste last, oltre a un offset per navigare all'interno di un livello. Chiameremo questo nuovo loop il nostro "elemento loop". Il loop degli elementi visiterà ogni elemento lungo la riga superiore, ogni elemento in basso a destra, ogni elemento in basso e ogni elemento in alto a sinistra.

  • Lo spostamento in avanti lungo la riga superiore richiede l'incremento dell'indice di colonna.
  • Lo spostamento verso il basso sul lato destro richiede l'incremento dell'indice di riga.
  • Lo spostamento all'indietro nella parte inferiore richiede che l'indice di colonna sia ridotto.
  • Lo spostamento verso l'alto richiede la riduzione dell'indice di riga.

Sembra complesso, ma è reso semplice perché il numero di volte che incrementiamo e diminuiamo per ottenere quanto sopra rimane lo stesso lungo tutti e quattro i lati della matrice. Per esempio:

  • Sposta 1 elemento nella riga superiore.
  • Sposta 1 elemento verso il basso sul lato destro.
  • Sposta 1 elemento all'indietro lungo la riga inferiore.
  • Sposta 1 elemento in alto a sinistra.

Ciò significa che possiamo usare una singola variabile in combinazione con le variabili firste lastper spostarci all'interno di un livello. Potrebbe essere utile notare che spostarsi attraverso la riga superiore e il lato destro richiede entrambi un incremento. Muovendosi all'indietro lungo il fondo e verso l'alto sul lato sinistro entrambi richiedono un decremento.

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2

    # Move through layers (i.e. layer loop).
    for layer in range(0, layer_count):

            first = layer
            last = size - first - 1

            # Move within a single layer (i.e. element loop).
            for element in range(first, last):

                offset = element - first

                # 'element' increments column (across right)
                top_element = (first, element)
                # 'element' increments row (move down)
                right_side = (element, last)
                # 'last-offset' decrements column (across left)
                bottom = (last, last-offset)
                # 'last-offset' decrements row (move up)
                left_side = (last-offset, first)

                print 'top: %s' % (top)
                print 'right_side: %s' % (right_side)
                print 'bottom: %s' % (bottom)
                print 'left_side: %s' % (left_side)

Ora dobbiamo semplicemente assegnare la parte superiore alla parte destra, la parte destra alla parte inferiore, la parte inferiore alla parte sinistra e la parte sinistra alla parte superiore. Mettendo tutto insieme otteniamo:

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2

    for layer in range(0, layer_count):
        first = layer
        last = size - first - 1

        for element in range(first, last):
            offset = element - first

            top = matrix[first][element]
            right_side = matrix[element][last]
            bottom = matrix[last][last-offset]
            left_side = matrix[last-offset][first]

            matrix[first][element] = left_side
            matrix[element][last] = top
            matrix[last][last-offset] = right_side
            matrix[last-offset][first] = bottom

Data la matrice:

0,  1,  2  
3,  4,  5  
6,  7,  8 

La nostra rotatefunzione si traduce in:

6,  3,  0  
7,  4,  1  
8,  5,  2  

Inizialmente mi sentivo come "wow, la migliore spiegazione di sempre", ma dopo averlo letto un paio di volte (per assicurarmi di non perdere nulla di importante nel mare di parole), la mia opinione è cambiata in "uomo, capisco, posso continuiamo a muoverci per favore? " Ancora votato per aver impiegato quelle che devono essere state ore per comporre una risposta così elaborata.
Abhijit Sarkar,

1
@AbhijitSarkar - Grazie per il voto positivo e spero che almeno abbia aiutato in qualche modo. Certo, hai ragione, la mia risposta è prolissa. Ciò era tuttavia intenzionalmente in contrasto con la stragrande maggioranza delle risposte. Come ho detto all'inizio della mia risposta: "In questa risposta, i concetti chiave si ripetono, il ritmo è lento e intenzionalmente ripetitivo". Se hai modifiche che mantengono la chiarezza e la ripetitività necessarie ma riducono il conteggio delle parole, sono molto aperto ai suggerimenti. O semplicemente modifica :)
Jack,

@jack Davvero una buona spiegazione. Tuttavia, non ho potuto sopportare, come hai trovato offset = element - first and last = size - first - 1? Hai difficoltà a capirlo? Inoltre, l'ultimo offset è uguale all'offset?
ashishjmeshram,

1
TL; DR:list(zip(*reversed(your_list_of_lists)))
Boris,

127

Pitone:

rotated = list(zip(*original[::-1]))

e in senso antiorario:

rotated_ccw = list(zip(*original))[::-1]

Come funziona:

zip(*original)scambieranno gli assi di matrici 2d impilando gli elementi corrispondenti dagli elenchi in nuovi elenchi. (L' *operatore dice alla funzione di distribuire gli elenchi contenuti in argomenti)

>>> list(zip(*[[1,2,3],[4,5,6],[7,8,9]]))
[[1,4,7],[2,5,8],[3,6,9]]

L' [::-1]istruzione inverte gli elementi dell'array (vedere Fette estese o questa domanda ):

>>> [[1,2,3],[4,5,6],[7,8,9]][::-1]
[[7,8,9],[4,5,6],[1,2,3]]

Infine, la combinazione dei due comporterà la trasformazione della rotazione.

La modifica del posizionamento di [::-1]inverte gli elenchi in diversi livelli della matrice.


3
Credo che questo codice provenga da Peter Norvig: norvig.com/python-iaq.html
Josip

È possibile utilizzare zip(*reversed(original))anziché zip(*original[::-1])per evitare di creare una copia aggiuntiva dell'elenco originale.
Boris il

70

Eccone uno che esegue la rotazione in posizione invece di utilizzare un array completamente nuovo per contenere il risultato. Ho interrotto l'inizializzazione dell'array e la stampa. Funziona solo con matrici quadrate ma possono essere di qualsiasi dimensione. L'overhead della memoria è uguale alla dimensione di un elemento dell'array, quindi puoi fare la rotazione di un array di dimensioni che desideri.

int a[4][4];
int n = 4;
int tmp;
for (int i = 0; i < n / 2; i++)
{
    for (int j = i; j < n - i - 1; j++)
    {
        tmp             = a[i][j];
        a[i][j]         = a[j][n-i-1];
        a[j][n-i-1]     = a[n-i-1][n-j-1];
        a[n-i-1][n-j-1] = a[n-j-1][i];
        a[n-j-1][i]     = tmp;
    }
}

Vedo almeno un bug. Se hai intenzione di postare il codice, testalo o almeno dì di non averlo fatto.
Hugh Allen,

1
Dove? Sottolinealo e lo aggiusterò. L'ho provato e ha funzionato bene su array sia di dimensioni pari che dispari.
dagorym,

2
è una bellissima soluzione. La mente può eseguire tali prodezze se impostata allo scopo. da O (n2) a O (1)
MoveFast

2
Non è O (1); è ancora O (n ^ 2)
duma

11
È O (n ^ 2) con memoria O (1).
Neel

38

Ci sono tonnellate di buon codice qui, ma voglio solo mostrare cosa sta succedendo geometricamente in modo da poter capire un po 'meglio la logica del codice. Ecco come mi avvicinerei a questo.

prima di tutto, non confonderlo con la trasposizione che è molto semplice ..

l'idea di base è di trattarla come strati e ruotiamo uno strato alla volta.

diciamo che abbiamo un 4x4

1   2   3   4
5   6   7   8
9   10  11  12
13  14  15  16

dopo averlo ruotato di 90 in senso orario otteniamo

13  9   5   1
14  10  6   2   
15  11  7   3
16  12  8   4

quindi scomponiamo questo, prima ruotiamo essenzialmente i 4 angoli

1           4


13          16

quindi ruotiamo il seguente diamante che è in qualche modo obliquo

    2
            8
9       
        15

e poi il 2 ° diamante inclinato

        3
5           
            12
    14

in modo che si prenda cura del bordo esterno, quindi essenzialmente facciamo quel guscio alla volta fino a quando

infine il quadrato centrale (o se è strano solo l'ultimo elemento che non si muove)

6   7
10  11

quindi ora cerchiamo di capire gli indici di ogni livello, supponiamo di lavorare sempre con il livello più esterno, lo stiamo facendo

[0,0] -> [0,n-1], [0,n-1] -> [n-1,n-1], [n-1,n-1] -> [n-1,0], and [n-1,0] -> [0,0]
[0,1] -> [1,n-1], [1,n-2] -> [n-1,n-2], [n-1,n-2] -> [n-2,0], and [n-2,0] -> [0,1]
[0,2] -> [2,n-2], [2,n-2] -> [n-1,n-3], [n-1,n-3] -> [n-3,0], and [n-3,0] -> [0,2]

così via e così via fino a quando non siamo a metà del bordo

quindi in generale lo schema è

[0,i] -> [i,n-i], [i,n-i] -> [n-1,n-(i+1)], [n-1,n-(i+1)] -> [n-(i+1),0], and [n-(i+1),0] to [0,i]

cosa significa "a metà del bordo"? Vedo molti algoritmi in loop fino a N / 2 e altri in loop fino a N, ma non riesco a vedere da dove provenga N / 2.
PDN

Credo che sia la stessa soluzione fornita nel decifrare il colloquio di programmazione. Ma mi piace la spiegazione passo dopo passo. Molto gentile e approfondito.
Naphstor,

@PDN Questa risposta lo spiega in dettaglio.
Mathias Bynens,

35

Come ho detto nel mio precedente post, ecco un po 'di codice in C # che implementa una rotazione di matrice O (1) per matrice di qualsiasi dimensione. Per brevità e leggibilità non c'è controllo degli errori o controllo dell'intervallo. Il codice:

static void Main (string [] args)
{
  int [,]
    //  create an arbitrary matrix
    m = {{0, 1}, {2, 3}, {4, 5}};

  Matrix
    //  create wrappers for the data
    m1 = new Matrix (m),
    m2 = new Matrix (m),
    m3 = new Matrix (m);

  //  rotate the matricies in various ways - all are O(1)
  m1.RotateClockwise90 ();
  m2.Rotate180 ();
  m3.RotateAnitclockwise90 ();

  //  output the result of transforms
  System.Diagnostics.Trace.WriteLine (m1.ToString ());
  System.Diagnostics.Trace.WriteLine (m2.ToString ());
  System.Diagnostics.Trace.WriteLine (m3.ToString ());
}

class Matrix
{
  enum Rotation
  {
    None,
    Clockwise90,
    Clockwise180,
    Clockwise270
  }

  public Matrix (int [,] matrix)
  {
    m_matrix = matrix;
    m_rotation = Rotation.None;
  }

  //  the transformation routines
  public void RotateClockwise90 ()
  {
    m_rotation = (Rotation) (((int) m_rotation + 1) & 3);
  }

  public void Rotate180 ()
  {
    m_rotation = (Rotation) (((int) m_rotation + 2) & 3);
  }

  public void RotateAnitclockwise90 ()
  {
    m_rotation = (Rotation) (((int) m_rotation + 3) & 3);
  }

  //  accessor property to make class look like a two dimensional array
  public int this [int row, int column]
  {
    get
    {
      int
        value = 0;

      switch (m_rotation)
      {
      case Rotation.None:
        value = m_matrix [row, column];
        break;

      case Rotation.Clockwise90:
        value = m_matrix [m_matrix.GetUpperBound (0) - column, row];
        break;

      case Rotation.Clockwise180:
        value = m_matrix [m_matrix.GetUpperBound (0) - row, m_matrix.GetUpperBound (1) - column];
        break;

      case Rotation.Clockwise270:
        value = m_matrix [column, m_matrix.GetUpperBound (1) - row];
        break;
      }

      return value;
    }

    set
    {
      switch (m_rotation)
      {
      case Rotation.None:
        m_matrix [row, column] = value;
        break;

      case Rotation.Clockwise90:
        m_matrix [m_matrix.GetUpperBound (0) - column, row] = value;
        break;

      case Rotation.Clockwise180:
        m_matrix [m_matrix.GetUpperBound (0) - row, m_matrix.GetUpperBound (1) - column] = value;
        break;

      case Rotation.Clockwise270:
        m_matrix [column, m_matrix.GetUpperBound (1) - row] = value;
        break;
      }
    }
  }

  //  creates a string with the matrix values
  public override string ToString ()
  {
    int
      num_rows = 0,
      num_columns = 0;

    switch (m_rotation)
    {
    case Rotation.None:
    case Rotation.Clockwise180:
      num_rows = m_matrix.GetUpperBound (0);
      num_columns = m_matrix.GetUpperBound (1);
      break;

    case Rotation.Clockwise90:
    case Rotation.Clockwise270:
      num_rows = m_matrix.GetUpperBound (1);
      num_columns = m_matrix.GetUpperBound (0);
      break;
    }

    StringBuilder
      output = new StringBuilder ();

    output.Append ("{");

    for (int row = 0 ; row <= num_rows ; ++row)
    {
      if (row != 0)
      {
        output.Append (", ");
      }

      output.Append ("{");

      for (int column = 0 ; column <= num_columns ; ++column)
      {
        if (column != 0)
        {
          output.Append (", ");
        }

        output.Append (this [row, column].ToString ());
      }

      output.Append ("}");
    }

    output.Append ("}");

    return output.ToString ();
  }

  int [,]
    //  the original matrix
    m_matrix;

  Rotation
    //  the current view of the matrix
    m_rotation;
}

OK, alzerò la mano, in realtà non fa alcuna modifica alla matrice originale durante la rotazione. Ma, in un sistema OO che non ha importanza finché l'oggetto sembra essere stato ruotato verso i client della classe. Al momento, la classe Matrix utilizza riferimenti ai dati dell'array originale, quindi la modifica di qualsiasi valore di m1 cambierà anche m2 e m3. Una piccola modifica al costruttore per creare un nuovo array e copiarne i valori lo risolverà.


4
Bravo! Questa è una soluzione molto bella e non so perché non sia la risposta accettata.
martinatime

@martinatime: forse perché è 5 volte più grande
Rospo

@Toad: la scrittura del codice è sempre un compromesso tra requisiti concorrenti: velocità, dimensioni, costo, ecc.
Skizz

15
vero ... un altro problema è il fatto che la matrice non è in realtà ruotata, ma è ruotata "just in time". Il che è ottimo per accedere ad alcuni elementi, ma sarebbe orribile se questa matrice fosse utilizzata nei calcoli o nelle manipolazioni delle immagini. Quindi dire O (1) non è proprio giusto.
Rospo

23

Mentre potrebbe essere necessario ruotare i dati in atto (forse per aggiornare la rappresentazione memorizzata fisicamente), diventa più semplice e forse più performante aggiungere uno strato di indiretta all'accesso dell'array, forse un'interfaccia:

interface IReadableMatrix
{
    int GetValue(int x, int y);
}

Se hai Matrixgià implementato questa interfaccia, allora può essere ruotata tramite una classe decoratore come questa:

class RotatedMatrix : IReadableMatrix
{
    private readonly IReadableMatrix _baseMatrix;

    public RotatedMatrix(IReadableMatrix baseMatrix)
    {
        _baseMatrix = baseMatrix;
    }

    int GetValue(int x, int y)
    {
        // transpose x and y dimensions
        return _baseMatrix(y, x);
    }
}

Anche in questo modo è possibile ruotare di + 90 / -90 / 180 gradi, capovolgere orizzontalmente / verticalmente e ridimensionare.

Le prestazioni dovrebbero essere misurate nel tuo scenario specifico. Tuttavia, l'operazione O (n ^ 2) è stata ora sostituita con una chiamata O (1). È una chiamata al metodo virtuale che è più lenta dell'accesso diretto all'array, quindi dipende dalla frequenza con cui l'array ruotato viene utilizzato dopo la rotazione. Se usato una volta, questo approccio vincerebbe sicuramente. Se viene ruotato e quindi utilizzato in un sistema di lunga durata per giorni, la rotazione sul posto potrebbe funzionare meglio. Dipende anche se è possibile accettare il costo iniziale.

Come per tutti i problemi di prestazioni, misura, misura, misura!


1
+1 ... E se la matrice è davvero grande e si accede solo a un paio di elementi (uso scarso) è ancora più efficace
lothar

16
Sembra un po 'ingiusto definire questa una soluzione temporale O (1). Per risolvere il problema posto dall'OP questo richiederà ancora tempo O (n ^ 2). Non solo, non risolverebbe il problema perché restituisce la trasposizione . L'esempio fornito non ha la trasposizione come soluzione.
Vlad l'Impala,

5
Ora, se tutto ciò che volevi erano i primi 3 elementi della matrice, questa è una soluzione eccellente, ma il problema è recuperare una matrice completamente trasformata (cioè supponendo che tu abbia bisogno di tutti gli elementi della matrice). Chiamare questo O (1) è il metodo Credit Default Swap di Algorithm Analysis - non hai risolto il problema, l'hai appena inviato a qualcun altro :)
Ana Betts,

4
@Paul Betts: Capisco, ma come ho scritto sopra nei commenti, anche se in realtà hai trasposto la matrice devi comunque scrivere il ciclo se vuoi leggere i valori. Quindi la lettura di tutti i valori da una matrice è sempre O (N ^ 2) a prescindere. La differenza qui è che se trasponi, ruoti, ridimensioni, ridimensioni di nuovo, ecc., Allora prendi il colpo O (N ^ 2) solo una volta. Come ho detto, questa non è sempre la soluzione migliore, ma in molti casi è appropriata e utile. L'OP sembrava cercare una soluzione magica, e questo è il più vicino possibile.
Drew Noakes,

9
Mi piace questa risposta, ma voglio sottolineare qualcosa. Stampare la matrice decorata (e fare altre letture sequenziali in generale) può essere molto più lento che fare lo stesso con una matrice che è stata ruotata in memoria, e non è solo a causa delle chiamate al metodo virtuale. Per una matrice di grandi dimensioni, aumenterai notevolmente il numero di errori nella cache che ricevi leggendo "giù" anziché "attraverso".
Mike Daniels,

18

Questa è una versione migliore di Java: l'ho fatta per una matrice con larghezza e altezza diverse

  • h è qui l'altezza della matrice dopo la rotazione
  • w è qui la larghezza della matrice dopo la rotazione

 

public int[][] rotateMatrixRight(int[][] matrix)
{
    /* W and H are already swapped */
    int w = matrix.length;
    int h = matrix[0].length;
    int[][] ret = new int[h][w];
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            ret[i][j] = matrix[w - j - 1][i];
        }
    }
    return ret;
}


public int[][] rotateMatrixLeft(int[][] matrix)
{
    /* W and H are already swapped */
    int w = matrix.length;
    int h = matrix[0].length;   
    int[][] ret = new int[h][w];
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            ret[i][j] = matrix[j][h - i - 1];
        }
    }
    return ret;
}

Questo codice si basa sul post di Nick Berardi.


Grazie. Questo era il codice Java più chiaro qui. Domanda - Come hai fatto tu / Nick a inventare la parte [w - j - 1]? Guardando la risposta @tweaking posso vedere come potresti ricavarlo attraverso esempi di induzione / risoluzione. Mi chiedo solo se è stato ottenuto o se si basa su alcuni principi matematici relativi alle matrici.
Quest Monger,

17

Ruby-modo: .transpose.map &:reverse


1
È ancora più semplice di quello: array.reverse.transposeruota un array in senso orario, mentre lo array.transpose.reverseruota in senso antiorario. Non ce n'è bisogno map.
Giorgi Gzirishvili l'

13

Ci sono già molte risposte e ho trovato due rivendicazioni O (1) complessità temporale. Il vero algoritmo O (1) è quello di lasciare intatta la memoria dell'array e cambiare il modo in cui si indicizzano i suoi elementi. L'obiettivo qui è che non consuma memoria aggiuntiva, né richiede tempo aggiuntivo per iterare i dati.

Le rotazioni di 90, -90 e 180 gradi sono semplici trasformazioni che possono essere eseguite purché si sappia quante righe e colonne sono presenti nell'array 2D; Per ruotare qualsiasi vettore di 90 gradi, scambiare gli assi e annullare l'asse Y. Per -90 gradi, scambiare gli assi e annullare l'asse X. Per 180 gradi, negare entrambi gli assi senza scambiare.

Sono possibili ulteriori trasformazioni, come il mirroring in orizzontale e / o in verticale, negando gli assi in modo indipendente.

Questo può essere fatto, ad esempio, con un metodo di accesso. Gli esempi seguenti sono funzioni JavaScript, ma i concetti si applicano ugualmente a tutte le lingue.

 // Get an array element in column/row order
 var getArray2d = function(a, x, y) {
   return a[y][x];
 };

 //demo
 var arr = [
   [5, 4, 6],
   [1, 7, 9],
   [-2, 11, 0],
   [8, 21, -3],
   [3, -1, 2]
 ];

 var newarr = [];
 arr[0].forEach(() => newarr.push(new Array(arr.length)));

 for (var i = 0; i < newarr.length; i++) {
   for (var j = 0; j < newarr[0].length; j++) {
     newarr[i][j] = getArray2d(arr, i, j);
   }
 }
 console.log(newarr);

// Get an array element rotated 90 degrees clockwise
function getArray2dCW(a, x, y) {
  var t = x;
  x = y;
  y = a.length - t - 1;
  return a[y][x];
}

//demo
var arr = [
  [5, 4, 6],
  [1, 7, 9],
  [-2, 11, 0],
  [8, 21, -3],
  [3, -1, 2]
];

var newarr = [];
arr[0].forEach(() => newarr.push(new Array(arr.length)));

for (var i = 0; i < newarr[0].length; i++) {
  for (var j = 0; j < newarr.length; j++) {
    newarr[j][i] = getArray2dCW(arr, i, j);
  }
}
console.log(newarr);

// Get an array element rotated 90 degrees counter-clockwise
function getArray2dCCW(a, x, y) {
  var t = x;
  x = a[0].length - y - 1;
  y = t;
  return a[y][x];
}

//demo
var arr = [
  [5, 4, 6],
  [1, 7, 9],
  [-2, 11, 0],
  [8, 21, -3],
  [3, -1, 2]
];

var newarr = [];
arr[0].forEach(() => newarr.push(new Array(arr.length)));

for (var i = 0; i < newarr[0].length; i++) {
  for (var j = 0; j < newarr.length; j++) {
    newarr[j][i] = getArray2dCCW(arr, i, j);
  }
}
console.log(newarr);

// Get an array element rotated 180 degrees
function getArray2d180(a, x, y) {
  x = a[0].length - x - 1;
  y = a.length - y - 1;
  return a[y][x];
}

//demo
var arr = [
  [5, 4, 6],
  [1, 7, 9],
  [-2, 11, 0],
  [8, 21, -3],
  [3, -1, 2]
];

var newarr = [];
arr.forEach(() => newarr.push(new Array(arr[0].length)));

for (var i = 0; i < newarr[0].length; i++) {
  for (var j = 0; j < newarr.length; j++) {
    newarr[j][i] = getArray2d180(arr, i, j);
  }
}
console.log(newarr);

Questo codice presuppone una matrice di matrici nidificate, in cui ogni matrice interna è una riga.

Il metodo consente di leggere (o scrivere) elementi (anche in ordine casuale) come se l'array fosse stato ruotato o trasformato. Ora scegli la funzione giusta da chiamare, probabilmente per riferimento, e via!

Il concetto può essere esteso per applicare le trasformazioni in modo additivo (e non distruttivo) attraverso i metodi di accesso. Incluse rotazioni angolari arbitrarie e ridimensionamento.


Tuttavia, nessuno di questi ha effettivamente ruotato dall'array originale. Il primo, il risultato finale è semplicemente trasposto. Il secondo, sembra che tu abbia appena mescolato le file o specchiato sul centro orizzontale. Il terzo, hai solo invertito le righe e anche il quarto è stato trasposto. Nessuno dei quali è stato effettivamente "ruotato".
SM177Y,

Ci sono alcuni bug negli ultimi due esempi. Triviale da risolvere. Ho sottolineato esplicitamente che questa soluzione non è una rotazione sul posto. È una funzione di trasformazione, che lo rende adatto per l'iterazione lenta.
Jason Oster,

Tranne che non c'è rotazione, quindi non hai effettivamente risposto a ciò che l'OP ha chiesto.
SM177Y,

@ SM177Y Un altro editor ha aggiunto un codice di esempio non funzionante alla mia risposta. Posso vedere come ne sei stato confuso. Ho corretto i bug nei cicli di iterazione. Le funzioni fornite infatti "ruotano" i dati nelle matrici.
Jason Oster,

Un altro dettaglio importante è che il codice di esempio elimina davvero la risposta originale che ho fornito, che stava cercando di illustrare il potere delle trasformazioni funzionali su soluzioni di complessità spazio-temporale lineari. Con una trasformazione funzionale stai già iterando o accedendo in altro modo agli elementi dell'array , quindi la trasformazione è considerata "libera" nel senso di spazio costante e complessità temporale.
Jason Oster,

10

Un paio di persone hanno già fornito esempi che implicano la creazione di un nuovo array.

Alcune altre cose da considerare:

(a) Invece di spostare effettivamente i dati, è sufficiente attraversare l'array "ruotato" in modo diverso.

(b) Fare la rotazione sul posto può essere un po 'più complicato. Avrai bisogno di un po 'di spazio per i graffi (probabilmente all'incirca uguale a una riga o colonna di dimensioni). C'è un antico documento ACM su come trasporre sul posto ( http://doi.acm.org/10.1145/355719.355729 ), ma il loro codice di esempio è FORTRAN malvagio.

Addendum:

http://doi.acm.org/10.1145/355611.355612 è un altro algoritmo di trasposizione sul posto presumibilmente superiore.


Sono d'accordo con questo. Utilizzare un metodo per determinare la traduzione tra i dati di origine e i dati "ruotati".
martinatime

8

La risposta di Nick avrebbe funzionato anche per un array NxM con solo una piccola modifica (al contrario di un NxN).

string[,] orig = new string[n, m];
string[,] rot = new string[m, n];

...

for ( int i=0; i < n; i++ )
  for ( int j=0; j < m; j++ )
    rot[j, n - i - 1] = orig[i, j];

Un modo di pensare a questo è che hai spostato il centro dell'asse (0,0) dall'angolo in alto a sinistra nell'angolo in alto a destra. Stai semplicemente trasponendo dall'uno all'altro.


6

Time - O (N), Space - O (1)

public void rotate(int[][] matrix) {
    int n = matrix.length;
    for (int i = 0; i < n / 2; i++) {
        int last = n - 1 - i;
        for (int j = i; j < last; j++) {
            int top = matrix[i][j];
            matrix[i][j] = matrix[last - j][i];
            matrix[last - j][i] = matrix[last][last - j];
            matrix[last][last - j] = matrix[j][last];
            matrix[j][last] = top;
        }
    }
}

Questo non è O (1). Questo è O (n).
Jason Oster,

@JasonOster Credo che questo sia O (1) spazio, poiché non consuma spazio aggiuntivo.
Sfogliando il

@ffledgling Il mio errore. O (1) complessità dello spazio, sì. O (n) complessità temporale.
Jason Oster,

Anche la complessità spaziale è O (n). La complessità spaziale dovrebbe includere lo spazio della dimensione della variabile di input. careercup.com/question?id=14952322
Jason Heo

Come potrei modificarlo per funzionare in senso antiorario?
MD XF,

5

Ecco la mia versione di Ruby (nota che i valori non sono visualizzati allo stesso modo, ma ruota comunque come descritto).

def rotate(matrix)
  result = []
  4.times { |x|
    result[x] = []
    4.times { |y|
      result[x][y] = matrix[y][3 - x]
    }
  }

  result
end

matrix = []
matrix[0] = [1,2,3,4]
matrix[1] = [5,6,7,8]
matrix[2] = [9,0,1,2]
matrix[3] = [3,4,5,6]

def print_matrix(matrix)
  4.times { |y|
    4.times { |x|
      print "#{matrix[x][y]} "
    }
    puts ""
  }
end

print_matrix(matrix)
puts ""
print_matrix(rotate(matrix))

Il risultato:

1 5 9 3 
2 6 0 4 
3 7 1 5 
4 8 2 6 

4 3 2 1 
8 7 6 5 
2 1 0 9 
6 5 4 3

4

ecco un metodo di rotazione nello spazio, di java, solo per square. per array 2D non quadrati, sarà comunque necessario creare un nuovo array.

private void rotateInSpace(int[][] arr) {
    int z = arr.length;
    for (int i = 0; i < z / 2; i++) {
        for (int j = 0; j < (z / 2 + z % 2); j++) {
            int x = i, y = j;
            int temp = arr[x][y];
            for (int k = 0; k < 4; k++) {
                int temptemp = arr[y][z - x - 1];
                arr[y][z - x - 1] = temp;
                temp = temptemp;

                int tempX = y;
                y = z - x - 1;
                x = tempX;
            }
        }
    }
}

codice per ruotare un array di qualsiasi dimensione 2d creando un nuovo array:

private int[][] rotate(int[][] arr) {
    int width = arr[0].length;
    int depth = arr.length;
    int[][] re = new int[width][depth];
    for (int i = 0; i < depth; i++) {
        for (int j = 0; j < width; j++) {
            re[j][depth - i - 1] = arr[i][j];
        }
    }
    return re;
}

3

Implementazione dello pseudocodice +90 della fossetta (ad es. Trasporre quindi invertire ogni riga) in JavaScript:

function rotate90(a){
  // transpose from http://www.codesuck.com/2012/02/transpose-javascript-array-in-one-line.html
  a = Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });
  // row reverse
  for (i in a){
    a[i] = a[i].reverse();
  }
  return a;
}

3

Puoi farlo in 3 semplici passaggi :

1 ) Supponiamo di avere una matrice

   1 2 3
   4 5 6
   7 8 9

2 ) Prendi la trasposizione della matrice

   1 4 7
   2 5 8
   3 6 9

3 ) Scambia le righe per ottenere la matrice ruotata

   3 6 9
   2 5 8
   1 4 7

Codice sorgente Java per questo:

public class MyClass {

    public static void main(String args[]) {
        Demo obj = new Demo();
        /*initial matrix to rotate*/
        int[][] matrix = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
        int[][] transpose = new int[3][3]; // matrix to store transpose

        obj.display(matrix);              // initial matrix

        obj.rotate(matrix, transpose);    // call rotate method
        System.out.println();
        obj.display(transpose);           // display the rotated matix
    }
}

class Demo {   
    public void rotate(int[][] mat, int[][] tran) {

        /* First take the transpose of the matrix */
        for (int i = 0; i < mat.length; i++) {
            for (int j = 0; j < mat.length; j++) {
                tran[i][j] = mat[j][i]; 
            }
        }

        /*
         * Interchange the rows of the transpose matrix to get rotated
         * matrix
         */
        for (int i = 0, j = tran.length - 1; i != j; i++, j--) {
            for (int k = 0; k < tran.length; k++) {
                swap(i, k, j, k, tran);
            }
        }
    }

    public void swap(int a, int b, int c, int d, int[][] arr) {
        int temp = arr[a][b];
        arr[a][b] = arr[c][d];
        arr[c][d] = temp;    
    }

    /* Method to display the matrix */
    public void display(int[][] arr) {
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr.length; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }
    }
}

Produzione:

1 2 3 
4 5 6 
7 8 9 

3 6 9 
2 5 8 
1 4 7 

2

Questa è la mia implementazione, nella complessità della memoria C, O (1), rotazione sul posto, 90 gradi in senso orario:

#include <stdio.h>

#define M_SIZE 5

static void initMatrix();
static void printMatrix();
static void rotateMatrix();

static int m[M_SIZE][M_SIZE];

int main(void){
    initMatrix();
    printMatrix();
    rotateMatrix();
    printMatrix();

    return 0;
}

static void initMatrix(){
    int i, j;

    for(i = 0; i < M_SIZE; i++){
        for(j = 0; j < M_SIZE; j++){
            m[i][j] = M_SIZE*i + j + 1;
        }
    }
}

static void printMatrix(){
    int i, j;

    printf("Matrix\n");
    for(i = 0; i < M_SIZE; i++){
        for(j = 0; j < M_SIZE; j++){
            printf("%02d ", m[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}

static void rotateMatrix(){
    int r, c;

    for(r = 0; r < M_SIZE/2; r++){
        for(c = r; c < M_SIZE - r - 1; c++){
            int tmp = m[r][c];

            m[r][c] = m[M_SIZE - c - 1][r];
            m[M_SIZE - c - 1][r] = m[M_SIZE - r - 1][M_SIZE - c - 1];
            m[M_SIZE - r - 1][M_SIZE - c - 1] = m[c][M_SIZE - r - 1];
            m[c][M_SIZE - r - 1] = tmp;
        }
    }
}

2

Ecco la versione Java:

public static void rightRotate(int[][] matrix, int n) {
    for (int layer = 0; layer < n / 2; layer++) {
        int first = layer;
        int last = n - 1 - first;
        for (int i = first; i < last; i++) {
           int offset = i - first;
           int temp = matrix[first][i];
           matrix[first][i] = matrix[last-offset][first];
           matrix[last-offset][first] = matrix[last][last-offset];
           matrix[last][last-offset] = matrix[i][last];
           matrix[i][last] = temp;
        }
    }
}

il metodo prima ruota lo strato mostouter, quindi si sposta sullo strato interno in modo quadratico.


2

Da un punto di vista lineare, considera le matrici:

    1 2 3        0 0 1
A = 4 5 6    B = 0 1 0
    7 8 9        1 0 0

Ora prendi una trasposizione

     1 4 7
A' = 2 5 8
     3 6 9

E considera l'azione di A 'su B, o B su A'.
Rispettivamente:

      7 4 1          3 6 9
A'B = 8 5 2    BA' = 2 5 8
      9 6 3          1 4 7

Questo è espandibile per qualsiasi matrice nxn. E applicando questo concetto rapidamente nel codice:

void swapInSpace(int** mat, int r1, int c1, int r2, int c2)
{
    mat[r1][c1] ^= mat[r2][c2];
    mat[r2][c2] ^= mat[r1][c1];
    mat[r1][c1] ^= mat[r2][c2];
}

void transpose(int** mat, int size)
{
    for (int i = 0; i < size; i++)
    {
        for (int j = (i + 1); j < size; j++)
        {
            swapInSpace(mat, i, j, j, i);
        }
    }
}

void rotate(int** mat, int size)
{
    //Get transpose
    transpose(mat, size);

    //Swap columns
    for (int i = 0; i < size / 2; i++)
    {
        for (int j = 0; j < size; j++)
        {
            swapInSpace(mat, i, j, size - (i + 1), j);
        }
    }
}

2

Codice C # per ruotare [n, m] array 2D di 90 gradi a destra

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MatrixProject
{
    // mattrix class

    class Matrix{
        private int rows;
        private int cols;
        private int[,] matrix;

        public Matrix(int n){
            this.rows = n;
            this.cols = n;
            this.matrix = new int[this.rows,this.cols];

        }

        public Matrix(int n,int m){
            this.rows = n;
            this.cols = m;

            this.matrix = new int[this.rows,this.cols];
        }

        public void Show()
        {
            for (var i = 0; i < this.rows; i++)
            {
                for (var j = 0; j < this.cols; j++) {
                    Console.Write("{0,3}", this.matrix[i, j]);
                }
                Console.WriteLine();
            }                
        }

        public void ReadElements()
        {
           for (var i = 0; i < this.rows; i++)
                for (var j = 0; j < this.cols; j++)
                {
                    Console.Write("element[{0},{1}]=",i,j);
                    this.matrix[i, j] = Convert.ToInt32(Console.ReadLine());
                }            
        }


        // rotate [n,m] 2D array by 90 deg right
        public void Rotate90DegRight()
        {

            // create a mirror of current matrix
            int[,] mirror = this.matrix;

            // create a new matrix
            this.matrix = new int[this.cols, this.rows];

            for (int i = 0; i < this.rows; i++)
            {
                for (int j = 0; j < this.cols; j++)
                {
                    this.matrix[j, this.rows - i - 1] = mirror[i, j];
                }
            }

            // replace cols count with rows count
            int tmp = this.rows;
            this.rows = this.cols;
            this.cols = tmp;           
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Matrix myMatrix = new Matrix(3,4);
            Console.WriteLine("Enter matrix elements:");
            myMatrix.ReadElements();
            Console.WriteLine("Matrix elements are:");
            myMatrix.Show();
            myMatrix.Rotate90DegRight();
            Console.WriteLine("Matrix rotated at 90 deg are:");
            myMatrix.Show();
            Console.ReadLine();
        }
    }
}

Risultato:

    Enter matrix elements:
    element[0,0]=1
    element[0,1]=2
    element[0,2]=3
    element[0,3]=4
    element[1,0]=5
    element[1,1]=6
    element[1,2]=7
    element[1,3]=8
    element[2,0]=9
    element[2,1]=10
    element[2,2]=11
    element[2,3]=12
    Matrix elements are:
      1  2  3  4
      5  6  7  8
      9 10 11 12
    Matrix rotated at 90 deg are:
      9  5  1
     10  6  2
     11  7  3
     12  8  4

2

PHP:

<?php    
$a = array(array(1,2,3,4),array(5,6,7,8),array(9,0,1,2),array(3,4,5,6));
$b = array(); //result

while(count($a)>0)
{
    $b[count($a[0])-1][] = array_shift($a[0]);
    if (count($a[0])==0)
    {
         array_shift($a);
    }
}

Da PHP5.6, la trasposizione di array può essere eseguita con una array_map()chiamata sleak . In altre parole, le colonne vengono convertite in righe.

Codice: ( Demo )

$array = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 0, 1, 2],
    [3, 4, 5, 6]
];
$transposed = array_map(null, ...$array);

$ Trasposto:

[
    [1, 5, 9, 3],
    [2, 6, 0, 4],
    [3, 7, 1, 5],
    [4, 8, 2, 6]
]

1

For i:= 0 to X do For j := 0 to X do graphic[j][i] := graphic2[X-i][j]

X è la dimensione dell'array in cui si trova la grafica.


1

#transpose è un metodo standard della classe Array di Ruby, quindi:

% irb
irb(main):001:0> m = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 0, 1, 2], [3, 4, 5, 6]]
=> [[1, 2, 3, 4], [5, 6, 7, 8], [9, 0, 1, 2], [3, 4, 5, 6]] 
irb(main):002:0> m.reverse.transpose
=> [[3, 9, 5, 1], [4, 0, 6, 2], [5, 1, 7, 3], [6, 2, 8, 4]]

L'implementazione è una funzione di trasposizione n ^ 2 scritta in C. Puoi vederla qui: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-transpose scegliendo "click per attivare / disattivare la sorgente "accanto a" trasposizione ".

Ricordo meglio delle soluzioni O (n ^ 2), ma solo per matrici appositamente costruite (come matrici sparse)


1

Codice C per rotazione matrice di 90 gradi in senso orario IN POSIZIONE per qualsiasi matrice M * N

void rotateInPlace(int * arr[size][size], int row, int column){
    int i, j;
    int temp = row>column?row:column;
    int flipTill = row < column ? row : column;
    for(i=0;i<flipTill;i++){
        for(j=0;j<i;j++){
            swapArrayElements(arr, i, j);
        }
    }

    temp = j+1;

    for(i = row>column?i:0; i<row; i++){
            for(j=row<column?temp:0; j<column; j++){
                swapArrayElements(arr, i, j);
            }
    }

    for(i=0;i<column;i++){
        for(j=0;j<row/2;j++){
            temp = arr[i][j];
            arr[i][j] = arr[i][row-j-1];
            arr[i][row-j-1] = temp;
        }
    }
}

1

ecco la mia implementazione sul posto in C.

void rotateRight(int matrix[][SIZE], int length) {

    int layer = 0;

    for (int layer = 0; layer < length / 2; ++layer) {

        int first = layer;
        int last = length - 1 - layer;

        for (int i = first; i < last; ++i) {

            int topline = matrix[first][i];
            int rightcol = matrix[i][last];
            int bottomline = matrix[last][length - layer - 1 - i];
            int leftcol = matrix[length - layer - 1 - i][first];

            matrix[first][i] = leftcol;
            matrix[i][last] = topline;
            matrix[last][length - layer - 1 - i] = rightcol;
            matrix[length - layer - 1 - i][first] = bottomline;
        }
    }
}

1

Ecco il mio tentativo di rotazione a 90 gradi della matrice, che è una soluzione in 2 fasi in C. Innanzitutto trasporre la matrice in posizione, quindi scambiare i caratteri.

#define ROWS        5
#define COLS        5

void print_matrix_b(int B[][COLS], int rows, int cols) 
{
    for (int i = 0; i <= rows; i++) {
        for (int j = 0; j <=cols; j++) {
            printf("%d ", B[i][j]);
        }
        printf("\n");
    }
}

void swap_columns(int B[][COLS], int l, int r, int rows)
{
    int tmp;
    for (int i = 0; i <= rows; i++) {
        tmp = B[i][l];
        B[i][l] = B[i][r];
        B[i][r] = tmp;
    }
}


void matrix_2d_rotation(int B[][COLS], int rows, int cols)
{
    int tmp;
    // Transpose the matrix first
    for (int i = 0; i <= rows; i++) {
        for (int j = i; j <=cols; j++) {
            tmp = B[i][j];
            B[i][j] = B[j][i];
            B[j][i] = tmp;
        }
    }
    // Swap the first and last col and continue until
    // the middle.
    for (int i = 0; i < (cols / 2); i++)
        swap_columns(B, i, cols - i, rows);
}



int _tmain(int argc, _TCHAR* argv[])
{
    int B[ROWS][COLS] = { 
                  {1, 2, 3, 4, 5}, 
                      {6, 7, 8, 9, 10},
                          {11, 12, 13, 14, 15},
                          {16, 17, 18, 19, 20},
                          {21, 22, 23, 24, 25}
                        };

    matrix_2d_rotation(B, ROWS - 1, COLS - 1);

    print_matrix_b(B, ROWS - 1, COLS -1);
    return 0;
}

1

@dagorym: Aw, amico. Mi ero aggrappato a questo come un buon puzzle "Sono annoiato, cosa posso ponderare". Ho trovato il mio codice di trasposizione sul posto, ma sono arrivato qui per trovare il tuo praticamente identico al mio ... ah, beh. Eccolo in Ruby.

require 'pp'
n = 10
a = []
n.times { a << (1..n).to_a }

pp a

0.upto(n/2-1) do |i|
  i.upto(n-i-2) do |j|
    tmp             = a[i][j]
    a[i][j]         = a[n-j-1][i]
    a[n-j-1][i]     = a[n-i-1][n-j-1]
    a[n-i-1][n-j-1] = a[j][n-i-1]
    a[j][n-i-1]     = tmp
  end
end

pp a

1
short normal[4][4] = {{8,4,7,5},{3,4,5,7},{9,5,5,6},{3,3,3,3}};

short rotated[4][4];

for (int r = 0; r < 4; ++r)
{
  for (int c = 0; c < 4; ++c)
  {
    rotated[r][c] = normal[c][3-r];
  }
}

Semplice metodo C ++, quindi ci sarebbe un grande sovraccarico di memoria in un grande array.


Tra tutte queste risposte ho trovato e testato questo compatto e abbastanza da ruotare
dlewin
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.