Jak obrócić tablicę dwuwymiarową?

Zainspirowany postem Raymonda Chena , powiedzmy, że masz dwuwymiarową tablicę 4x4, napisz funkcję, która obraca ją o 90 stopni. Raymond linkuje do rozwiązania w pseudo kodzie, ale chciałbym zobaczyć coś z prawdziwego świata.

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

Staje się:

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

Update : odpowiedź Nicka jest najprostsza, ale czy jest sposób, aby zrobić to lepiej niż n^2? A gdyby matryca miała wymiary 10000x10000?

Author: swilliams, 2008-09-03

30 answers

Tutaj jest w 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;
}
 150
Author: Nick Berardi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 20:07:29

O(N^2) Czas i o (1) algorytm przestrzeni ( bez żadnych obejść i hanky-panky rzeczy! )

Obróć przez +90:

  1. Transpozycja
  2. Odwróć każdy wiersz

Obróć przez -90:

Metoda 1 :

  1. Transpozycja
  2. Odwróć każdą kolumnę

Metoda 2 :

  1. Odwróć każdy wiersz
  2. Transpozycja

Obróć przez +180:

metoda 1: Obróć o +90 dwa razy

Metoda 2 : Odwróć każdy wiersz, a następnie odwróć każdą kolumnę (Transpozycja)

Obróć przez -180:

Metoda 1 : Obróć dwukrotnie o -90

Metoda 2 : Odwróć każdą kolumnę, a następnie odwróć każdy wiersz

Metoda 3: Obróć o +180, ponieważ są takie same

 419
Author: dimple,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-22 10:14:47

Chciałbym dodać trochę więcej szczegółów. W tej odpowiedzi powtarzają się kluczowe pojęcia, tempo jest powolne i celowo powtarzalne. Przedstawione tutaj rozwiązanie nie jest najbardziej zwarte składniowo, jest jednak przeznaczone dla tych, którzy chcą dowiedzieć się, czym jest rotacja macierzy i wynikająca z tego implementacja.

Po pierwsze, czym jest matryca? Dla celów tej odpowiedzi macierz jest tylko siatką, w której szerokość i wysokość są takie same. Uwaga, szerokość i wysokość macierzy może być inaczej, ale dla uproszczenia, ten tutorial uwzględnia tylko macierze o równej szerokości i wysokości (macierze kwadratowe ). I tak, macierze jest liczbą mnogą macierzy.

Przykładowe macierze to: 2×2, 3×3 lub 5×5. Lub, bardziej ogólnie, N×N. macierz 2×2 będzie miała 4 kwadraty, ponieważ 2×2=4. Macierz 5×5 będzie miała 25 kwadratów, ponieważ 5×5=25. Każdy kwadrat nazywany jest elementem lub wejściem. Każdy element będzie reprezentowany kropką (.) na poniższych diagramach:

2×2 matrix

. .
. .

Macierz 3×3

. . .
. . .
. . .

4×4 macierz

. . . .
. . . .
. . . .
. . . .
Co to znaczy obracać matrycę? Weźmy macierz 2×2 i umieśćmy kilka liczb w każdym elemencie, aby można było zaobserwować obrót:
0 1
2 3

Obrót o 90 stopni daje nam:

2 0
3 1
Dosłownie przekręciliśmy całą matrycę raz w prawo, tak jak obracaliśmy kierownicę samochodu. Pomocne może być myślenie o" przewróceniu " matrycy na jej prawą stronę. Chcemy napisać funkcję, w Python, który bierze matrycę i obraca się raz w prawo. Sygnatura funkcji będzie:
def rotate(matrix):
    # Algorithm goes here.

Macierz będzie zdefiniowana za pomocą tablicy dwuwymiarowej:

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

Dlatego pierwsza pozycja indeksu uzyskuje dostęp do wiersza. Druga pozycja indeksu ma dostęp do kolumny:

matrix[row][column]

Zdefiniujemy funkcję użytkową do drukowania macierzy.

def print_matrix(matrix):
    for row in matrix:
        print row
Jedną z metod obracania matrycy jest robienie tego warstwą na raz. Ale co to jest warstwa? Pomyśl o cebuli. Tak jak w warstwy cebuli, jak każda warstwa jest usuwana, poruszamy się w kierunku środka. Inne analogie to Lalka Matryoshka lub gra pass-the-parcel.

Szerokość i wysokość macierzy dyktują liczbę warstw w tej macierzy. Zastosujmy różne symbole dla każdej warstwy:

Macierz 2×2 mA 1 warstwę

. .
. .

Macierz 3×3 ma 2 warstwy

. . .
. x .
. . .

Macierz 4×4 mA 2 warstwy

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

Macierz 5×5 mA 3 warstwy

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

Macierz 6×6 ma 3 warstwy

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

Macierz 7×7 ma 4 warstwy

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

Można zauważyć, że zwiększenie szerokości i wysokości matrycy o jeden, nie zawsze zwiększa liczbę warstw. Biorąc powyższe macierze i tabulując warstwy i wymiary, widzimy, że liczba warstw zwiększa się raz na dwa przyrosty szerokości i wysokości:

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

Jednak nie wszystkie warstwy wymagają obracania. Matryca 1×1 jest taka sama przed i po obrocie. Centralna warstwa 1×1 jest zawsze to samo przed i po rotacji, bez względu na to, jak duża jest ogólna macierz: {]}

+-----+--------+------------------+
| 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 |
+-----+--------+------------------+

Biorąc pod uwagę macierz N×N, jak możemy programowo określić liczbę warstw, które musimy obrócić? Jeśli podzielimy szerokość lub wysokość przez dwa i zignorujemy resztę, otrzymamy następujące wyniki.

+-----+--------+------------------+---------+
| 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 |
+-----+--------+------------------+---------+

Zauważ jak N/2 dopasowuje liczbę warstw, które należy obrócić? Czasami liczba obracających się warstw jest o jeden mniej całkowita liczba warstw w matrycy. Dzieje się tak, gdy najskrytsze warstwa jest utworzona tylko z jednego elementu (tj. matrycy 1×1) i dlatego nie musi być obracana. Po prostu zostaje zignorowany.

Bez wątpienia będziemy potrzebować tej informacji w naszej funkcji, aby obrócić macierz, więc dodajmy ją teraz:]}
def rotate(matrix):
    size = len(matrix)
    # Rotatable layers only.
    layer_count = size / 2

Teraz wiemy, jakie są warstwy i jak określić liczbę warstw, które faktycznie wymagają obracania, jak wyizolować pojedynczą warstwę, aby móc ją obracać? Po pierwsze, sprawdzamy matrycę od zewnętrznej warstwy, do wewnątrz, do najbardziej wewnętrznej warstwy. Matryca 5×5 ma w sumie trzy warstwy i dwie warstwy, które wymagają obracania: [61]}

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

Spójrzmy najpierw na kolumny. Pozycja kolumn definiujących zewnętrzną warstwę, zakładając, że liczymy od 0, wynosi 0 i 4:

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

0 i 4 są również pozycjami wierszy dla zewnętrznej warstwy.

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

Tak będzie zawsze, ponieważ szerokość i wysokość są takie same. Dlatego możemy zdefiniować pozycje kolumn i wierszy warstwy z tylko dwoma wartościami (zamiast cztery).

Przechodząc do drugiej warstwy, pozycja kolumn wynosi 1 i 3. I tak, zgadłeś, tak samo jest z rzędami. Ważne jest, aby zrozumieć, że musieliśmy zarówno zwiększać, jak i zmniejszać pozycje wierszy i kolumn podczas przechodzenia do następnej warstwy.

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

Aby sprawdzić każdą warstwę, potrzebujemy pętli z licznikami rosnącymi i malejącymi, które reprezentują poruszanie się do wewnątrz, zaczynając od zewnętrznej warstwy. Nazwiemy to naszą warstwą loop".

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)

Powyższy kod przecina pozycje (wiersz i Kolumna) wszystkich warstw, które wymagają obracania.

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

Mamy teraz pętlę określającą pozycje wierszy i kolumn każdej warstwy. Zmienne first i last określają pozycję indeksu pierwszego i ostatniego wiersza oraz kolumn. Odwołując się do naszych tabel wierszy i kolumn:

+--------+-----------+
| 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 | . . . . . |
+-----+-----------+
Więc możemy poruszać się po warstwach matrycy. Teraz potrzebujemy sposobu poruszania się w obrębie warstwy, abyśmy mogli poruszać się elementy wokół tej warstwy. Zauważ, że elementy nigdy nie "przeskakują" z jednej warstwy na drugą, ale poruszają się w obrębie poszczególnych warstw.

Obrócenie każdego elementu w warstwie obraca całą warstwę. Obracanie wszystkich warstw w matrycy obraca całą matrycę. To zdanie jest bardzo ważne, więc postaraj się jak najlepiej je zrozumieć, zanim przejdziesz dalej.

Teraz potrzebujemy sposobu rzeczywistego przemieszczania elementów, tzn. obracania każdego elementu, a następnie warstwy, a ostatecznie matrycy. Dla uproszczenia powrócimy do matrycy 3x3-która ma jedną obracalną warstwę.

0 1 2
3 4 5
6 7 8

Nasza pętla warstw zawiera indeksy pierwszej i ostatniej kolumny, a także pierwszego i ostatniego wiersza:

+-----+-------+
| 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 |
+-----+-------+

Ponieważ nasze macierze są zawsze kwadratowe, potrzebujemy tylko dwóch zmiennych, first i last, ponieważ pozycje indeksów są takie same dla wierszy i kolumn.

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.

Zmienne first I last mogą być łatwo użyte do odniesienia się do czterech narożników macierzy. To dlatego, że narożniki można je zdefiniować za pomocą różnych permutacji first i last (bez odejmowania, dodawania lub przesunięcia tych zmiennych):

+---------------+-------------------+-------------+
| 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)       |
+---------------+-------------------+-------------+

Z tego powodu rozpoczynamy obrót na zewnętrznych czterech rogach - najpierw obrócimy te. Zaznaczmy je *.

* 1 *
3 4 5
* 7 *

Chcemy zamienić każdy {[50] } z * na prawo od niego. Więc zróbmy Wydruk naszych narożników zdefiniowanych tylko za pomocą różnych permutacji first i 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)

Wyjście powinno być:

top_left: (0, 0)
top_right: (0, 2)
bottom_right: (2, 2)
bottom_left: (2, 0)
Teraz możemy łatwo zamienić każdy z rogów z naszej pętli warstwy:]}
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)

Macierz przed obracaniem rogów:

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

Macierz po obrotowych rogach:

[6, 1, 0]
[3, 4, 5]
[8, 7, 2]
Świetnie! Z powodzeniem obróciliśmy każdy róg matrycy. Ale nie obróciliśmy elementów na środku każdej warstwy. Najwyraźniej potrzebujemy sposobu na iterację w warstwie.

Problem polega na tym, że jedyna pętla w naszej funkcji (nasza pętla warstwy) przesuwa do następnej warstwy na każdej iteracji. Ponieważ nasza matryca ma tylko jedną obracalną warstwę, pętla warstwy wychodzi po obróceniu tylko rogów. Przyjrzyjmy się, co dzieje się z większą matrycą 5×5 (gdzie dwie warstwy wymagają obracania). Kod funkcji został pominięty, ale pozostaje taki sam jak powyżej:

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)

Wyjście to:

[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]

Nie powinno dziwić, że narożniki zewnętrznej warstwy zostały obrócone, ale można również zauważyć rogi następnej warstwy (do wewnątrz) zostały również obrócone. To ma sens. Napisaliśmy kod, aby poruszać się po warstwach, a także obracać rogi każdej warstwy. Wydaje się, że to postęp, ale niestety musimy zrobić krok wstecz. Po prostu nie jest dobrze przesuwać się na następną warstwę, dopóki poprzednia (zewnętrzna) warstwa nie zostanie całkowicie obrócona. Oznacza to, że aż każdy element w warstwie zostanie obrócony. Obracanie tylko rogów nie wystarczy!

Weź głęboki oddech. Potrzebujemy kolejnej pętli. Zagnieżdżona pętla nie mniej. Nowy, zagnieżdżony loop, będzie używać zmiennych first i last oraz offsetu do poruszania się po warstwie. Tę nową pętlę nazwiemy "pętlą elementu". Pętla elementu odwiedzi każdy element wzdłuż górnego wiersza, każdy element po prawej stronie, każdy element wzdłuż dolnego wiersza i każdy element po lewej stronie.
  • poruszanie się do przodu wzdłuż górnego wiersza wymaga kolumny indeks do zwiększenia.
  • poruszanie się po prawej stronie wymaga indeksu wiersza do be / align = "left" /
  • poruszanie się do tyłu wzdłuż dołu wymaga kolumny indeks zostanie zmniejszony.
  • poruszanie się po lewej stronie wymaga, aby indeks wiersza był / align = "left" /

To brzmi skomplikowanie, ale jest to łatwe, ponieważ liczba razy, które zwiększamy i zmniejszamy, aby osiągnąć powyższe, pozostaje taka sama wzdłuż wszystkich czterech stron matrycy. Na przykład:

  • Przesuń 1 element w górnym rzędzie.
  • Przesuń 1 element w prawo bok.
  • Przesuń 1 element do tyłu wzdłuż dolnego rzędu.
  • Przesuń 1 element w lewo.

Oznacza to, że możemy używać pojedynczej zmiennej w połączeniu ze zmiennymi first i last do poruszania się po warstwie. Może pomóc zauważyć, że poruszanie się po górnym rzędzie i w dół po prawej stronie wymaga zwiększenia. Podczas poruszania się do tyłu wzdłuż dołu i w górę po lewej stronie oba wymagają zmniejszania.

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 = (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)

Teraz po prostu musimy przypisać górę po prawej stronie, po prawej stronie na dole, na dole po lewej stronie, a po lewej stronie na górze. Składając to wszystko razem otrzymujemy:

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

Biorąc pod uwagę macierz:

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

Nasza rotate funkcja daje:

6,  3,  0  
7,  4,  1  
8,  5,  2  
 201
Author: Jack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-16 18:32:49

Python:

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

I przeciwnie do ruchu wskazówek zegara:

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

Jak to działa:

zip(*original) zamieni osie tablic 2d, układając odpowiednie pozycje z list w nowe listy. (The * operator mówi funkcji do dystrybucji zawartych list na argumenty)

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

Instrukcja [::-1] odwraca elementy tablicy (patrz Rozszerzone plasterki lub to pytanie):

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

Wreszcie, łącząc te dwa spowoduje transformację rotacyjną.

Zmiana położenia [::-1] spowoduje odwrócenie list na różnych poziomach macierzy.

 130
Author: bcdan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-28 07:44:05

Tutaj jest taki, który wykonuje obrót w miejscu, zamiast używać zupełnie nowej tablicy do przechowywania wyniku. Przerwałem inicjalizację tablicy i wydruk jej. Działa to tylko dla tablic kwadratowych, ale mogą one mieć dowolny rozmiar. Narzut pamięci jest równy rozmiarowi jednego elementu tablicy, więc możesz wykonać obrót tak dużej tablicy, jak chcesz.

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;
    }
}
 73
Author: dagorym,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-13 00:29:01

Jest tu mnóstwo dobrego kodu, ale chcę tylko pokazać, co się dzieje geometrycznie, abyś mógł lepiej zrozumieć logikę kodu. Oto, jak podchodziłbym do tego.

Po pierwsze, nie należy tego mylić z transpozycją, która jest bardzo łatwa..

Ideą basica jest traktowanie go jako warstwy i obracamy jedną warstwę na raz..

Powiedzmy, że mamy 4x4

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

Po obróceniu go zgodnie z ruchem wskazówek zegara o 90 otrzymujemy

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

Więc rozkładajmy to, najpierw obróć 4 rogi zasadniczo

1           4


13          16

Następnie obracamy następujący diament, który jest rodzajem krzywizny

    2
            8
9       
        15

A potem drugi skośny diament

        3
5           
            12
    14

Tak, że zajmuje się zewnętrzną krawędzią, więc zasadniczo robimy tę jedną powłokę na raz, aż

Wreszcie środkowy kwadrat (lub jeśli jest nieparzysty tylko ostatni element, który się nie porusza)

6   7
10  11

Więc teraz ustalmy indeksy każdej warstwy, Załóżmy, że zawsze pracujemy z zewnętrzną warstwą, jesteśmy doing

[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]

Tak dalej i tak dalej dopóki nie będziemy w połowie Krawędzi

Więc ogólnie wzór jest

[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]
 38
Author: tweaking,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-25 17:56:28

Jak już mówiłem w poprzednim poście, oto kod w C#, który implementuje rotację o(1) macierzy dla dowolnej wielkości macierzy. Dla zwięzłości i czytelności nie ma sprawdzania błędów ani sprawdzania zakresu. Kod:

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, podniosę rękę, to nie robi żadnych modyfikacji oryginalnej tablicy podczas obracania. Ale w systemie OO, który nie ma znaczenia, dopóki obiekt wygląda tak, jakby został obrócony do klientów klasy. W tej chwili Klasa Matrix używa odniesień do oryginalne dane tablicy, więc zmiana dowolnej wartości m1 spowoduje również zmianę m2 i m3. Mała zmiana konstruktora w celu utworzenia nowej tablicy i skopiowania do niej wartości rozwiąże ten problem.

 37
Author: Skizz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 20:07:46

Podczas gdy rotacja danych w miejscu może być konieczna (być może w celu aktualizacji fizycznie przechowywanej reprezentacji), łatwiejsze i prawdopodobnie bardziej wydajne staje się dodanie warstwy indrection do dostępu do tablicy, być może interfejsu:

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

Jeśli Twój Matrix już implementuje ten interfejs, to można go obracać za pomocą klasy decorator w następujący sposób:

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);
    }
}

Obracanie +90/-90/180 stopni, przerzucanie poziomo / pionowo i skalowanie można osiągnąć w tym Moda również.

Wydajność musi być mierzona w konkretnym scenariuszu. Jednakże operacja O (N^2) została zastąpiona wywołaniem O(1). Jest to wirtualne wywołanie metody, które jest wolniejsze niż bezpośredni dostęp do tablicy, więc zależy to od tego, jak często używana jest obrócona tablica po obróceniu. Jeśli zostanie użyty raz, to takie podejście zdecydowanie wygra. Jeśli jest obracany, a następnie używany w długotrwałym systemie przez kilka dni, rotacja na miejscu może działać lepiej. To także zależy, czy możesz zaakceptować koszty z góry.

Jak w przypadku wszystkich problemów z wydajnością, miara, miara, miara!

 24
Author: Drew Noakes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 20:09:37

To lepsza wersja w Javie: zrobiłem ją dla matrycy o innej szerokości i wysokości

  • h jest tutaj wysokością macierzy po obróceniu
  • w jest tu szerokością macierzy po obróceniu

 

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;
}

Ten kod jest oparty na wpisie Nicka Berardi.

 18
Author: Martijn Courteaux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 20:10:05

Ruby-way: .transpose.map &:reverse

 18
Author: Nakilon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-12 01:38:36

Jest już wiele odpowiedzi i znalazłem dwie twierdzące o (1) złożoności czasowej. Algorytm real O(1) polega na pozostawieniu pamięci tablicy nietkniętej i zmianie sposobu indeksowania jej elementów. Celem jest to, że nie zużywa dodatkowej pamięci, ani nie wymaga dodatkowego czasu na iterację danych.

Obroty o 90, -90 i 180 stopni są prostymi transformacjami, które można wykonać tak długo, jak wiesz, ile wierszy i kolumn znajduje się w tablicy 2D; aby obrócić dowolny wektor o 90 stopni, zamień osie i neguj Oś Y. Dla -90 stopni, zamień osie i neguj oś X. Dla 180 stopni neguj obie osie bez wymiany.

Możliwe są dalsze przekształcenia, takie jak dublowanie poziomo i/lub pionowo przez niezależne negowanie osi.

Można to zrobić za pomocą np. metody accessora. Poniższe przykłady to funkcje JavaScript, ale pojęcia te odnoszą się jednakowo do wszystkich języki.

 // 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);

Ten kod zakłada tablicę zagnieżdżonych tablic, gdzie każda tablica wewnętrzna jest wierszem.

Metoda pozwala na odczyt (lub zapis) elementów (nawet w losowej kolejności) tak, jakby tablica została obrócona lub przekształcona. Teraz po prostu wybierz odpowiednią funkcję do wywołania, prawdopodobnie przez odniesienie,i gotowe!

Pojęcie można rozszerzyć o zastosowanie przekształceń addytywnie (i nieniszcząco) za pomocą metod accessor. W tym dowolne obroty kąta i skalowanie.

 13
Author: Jason Oster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-27 05:26:26

Kilka osób już podało przykłady, które wiążą się z tworzeniem nowej tablicy.

Kilka innych rzeczy do rozważenia:

(a) zamiast faktycznie przenosić dane, po prostu przemierzaj "obróconą" tablicę w inny sposób.

(b) Wykonywanie rotacji w miejscu może być trochę trudniejsze. Będziesz potrzebował trochę miejsca na zarysowania(prawdopodobnie mniej więcej równego jednemu wierszowi lub kolumnie). Jest antyczna Gazeta ACM o robieniu transponow na miejscu ( http://doi.acm.org/10.1145/355719.355729 ), ale ich przykładowy kod to paskudny Goto-obciążony FORTRAN.

Dodatek:

Http://doi.acm.org/10.1145/355611.355612 {[8] } jest kolejnym, rzekomo nadrzędnym algorytmem transpozycyjnym.

 10
Author: nsanders,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-03 22:09:53

Odpowiedź Nicka będzie działać również dla tablicy NxM z tylko małą modyfikacją (w przeciwieństwie do 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];

Jednym ze sposobów myślenia o tym jest przesunięcie środka osi (0,0) z lewego górnego rogu do prawego górnego rogu. Po prostu transponujesz z jednego do drugiego.

 9
Author: Kevin Berridge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:26

Czas - O (N), Przestrzeń-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;
        }
    }
}
 6
Author: user2793692,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-22 02:58:24

Oto moja wersja Ruby (zauważ, że wartości nie są wyświetlane tak samo, ale nadal obraca się zgodnie z opisem).

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))

Wyjście:

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
 5
Author: Mike Stone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 20:11:10

Oto metoda rotacji w przestrzeni, w Javie, tylko dla kwadratu. w przypadku nie kwadratowej tablicy 2d i tak będziesz musiał utworzyć nową tablicę.

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;
            }
        }
    }
}

Kod do obrócenia dowolnej tablicy 2d poprzez utworzenie nowej tablicy:

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;
}
 4
Author: James Yu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 20:12:42

Implementacja pseudokodu dimple ' a + 90 (np. transpozycja następnie odwrócenie każdego wiersza) w 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
Author: mhawksey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 20:16:43

Możesz to zrobić w 3 prostych krokach :

1)Załóżmy, że mamy macierz

   1 2 3
   4 5 6
   7 8 9

2)Weźmy transpozycję macierzy

   1 4 7
   2 5 8
   3 6 9

3)Interchange rows to get rotated matrix

   3 6 9
   2 5 8
   1 4 7

Java kod źródłowy do tego:

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();
        }
    }
}

Wyjście:

1 2 3 
4 5 6 
7 8 9 

3 6 9 
2 5 8 
1 4 7 
 3
Author: Prateek Joshi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-30 18:09:28

To jest moja implementacja, w C, O(1) złożoności pamięci, w miejscu obrotu, 90 stopni zgodnie z ruchem wskazówek zegara:

#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
Author: Spidey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 20:12:56

Oto Wersja Javy:

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;
        }
    }
}

Metoda najpierw obraca warstwę mostoutera, a następnie przesuwa się do warstwy wewnętrznej kwadratowo.

 2
Author: radium,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 20:16:16

Z liniowego punktu widzenia rozważmy macierze:

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

Teraz weź transpozycję

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

I rozważmy działanie a 'na B, lub B na A'.
Odpowiednio:

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

Jest to rozszerzalne dla dowolnej macierzy n x N. I zastosowanie tego pojęcia szybko w kodzie:

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
Author: Mr. Nex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-12 00:47:57

Kod C # do obracania [n,m] tablic 2D o 90 stopni w prawo

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();
        }
    }
}

Wynik:

    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
Author: ustmaestro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-19 15:22:52

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);
    }
}

Od PHP5.6 transpozycja tablicy może być wykonywana za pomocą sleak array_map(). Innymi słowy, kolumny są konwertowane na wiersze.

Code: (Demo )

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

$transposed:

[
    [1, 5, 9, 3],
    [2, 6, 0, 4],
    [3, 7, 1, 5],
    [4, 8, 2, 6]
]
 2
Author: James Lin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-09 07:19:47

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

X jest rozmiarem tablicy, w której znajduje się grafika.

 1
Author: Turk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-29 14:13:18

#transpose jest standardową metodą klasy tablicowej Ruby, zatem:

% 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]]

Implementacja jest funkcją transpozycyjną n^2 napisaną w języku C. możesz ją zobaczyć tutaj: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-transpose wybierając "Kliknij, aby przełączyć źródło "obok " transpozycja".

Przypominam sobie lepsze rozwiązania niż O (n^2), ale tylko dla specjalnie skonstruowanych macierzy (np.]}

 1
Author: k00ka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-27 21:05:43

Kod C dla obrotu macierzy o 90 stopni zgodnie z ruchem wskazówek zegara dla dowolnej macierzy 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
Author: rohitmb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 20:13:10

Oto moja implementacja w 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
Author: thiagoh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 20:13:29

Oto moja próba rotacji matrycy 90 stopni, która jest 2-stopniowym rozwiązaniem w C. najpierw TRANSPONUJ matrycę na miejsce, a następnie zamień cols.

#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
Author: user1596193,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 20:13:57

@ Dagorym: aw, man. Trzymałem się tego jako dobrą łamigłówkę "nudzę się, nad czym mogę się zastanowić". Wymyśliłem mój kod transpozycyjny, ale znalazłem Twój prawie identyczny jak mój...no cóż. Jest w 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
Author: Nathan Fritz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 20:15:09
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];
  }
}

Prosta metoda C++, ponieważ w dużej tablicy byłaby duża pamięć.

 1
Author: William,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 20:15:41