367 Stimmen

Wie kann man ein zweidimensionales Feld drehen?

Inspiriert durch Beitrag von Raymond Chen Wenn Sie ein zweidimensionales 4x4-Array haben, schreiben Sie eine Funktion, die es um 90 Grad dreht. Raymond verlinkt auf eine Lösung in Pseudocode, aber ich würde gerne etwas aus der Praxis sehen.

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

Wird:

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

Update : Die Antwort von Nick ist die einfachste, aber gibt es eine Möglichkeit, es besser zu machen als n^2? Was wäre, wenn die Matrix 10000x10000 wäre?

16voto

Jason Oster Punkte 1326

Es gibt bereits viele Antworten, und ich habe zwei gefunden, die eine Zeitkomplexität von O(1) angeben. Die real O(1)-Algorithmus besteht darin, den Array-Speicher unangetastet zu lassen und die Indizierung der Elemente zu ändern. Das Ziel dabei ist, dass weder zusätzlicher Speicherplatz noch zusätzliche Zeit für die Iteration der Daten benötigt wird.

Drehungen um 90, -90 und 180 Grad sind einfache Transformationen, die durchgeführt werden können, wenn Sie wissen, wie viele Zeilen und Spalten Ihr 2D-Array hat. Um einen beliebigen Vektor um 90 Grad zu drehen, vertauschen Sie die Achsen und negieren die Y-Achse. Für -90 Grad vertauschen Sie die Achsen und negieren die X-Achse. Für 180 Grad negieren Sie beide Achsen, ohne sie zu vertauschen.

Weitere Transformationen sind möglich, z. B. eine horizontale und/oder vertikale Spiegelung durch unabhängige Negierung der Achsen.

Dies kann z. B. durch eine Accessor-Methode geschehen. Bei den folgenden Beispielen handelt es sich um JavaScript-Funktionen, aber die Konzepte gelten für alle Sprachen gleichermaßen.

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

Dieser Code geht von einem Array aus verschachtelten Arrays aus, wobei jedes innere Array eine Zeile ist.

Mit dieser Methode können Sie Elemente (auch in zufälliger Reihenfolge) lesen (oder schreiben), als ob das Array gedreht oder transformiert worden wäre. Jetzt müssen Sie nur noch die richtige Funktion zum Aufrufen auswählen, wahrscheinlich per Referenz, und schon kann es losgehen!

Das Konzept kann erweitert werden, um Transformationen additiv (und nicht-destruktiv) über die Accessor-Methoden anzuwenden. Einschließlich beliebiger Winkeldrehungen und Skalierungen.

10voto

nsanders Punkte 11482

Einige Leute haben bereits Beispiele genannt, bei denen ein neues Array erstellt wird.

Ein paar andere Dinge sind zu beachten:

(a) Anstatt die Daten tatsächlich zu verschieben, wird das "gedrehte" Feld einfach anders durchlaufen.

(b) Die Drehung an Ort und Stelle kann ein wenig schwieriger sein. Sie brauchen ein wenig Platz zum Kratzen (wahrscheinlich etwa so groß wie eine Zeile oder Spalte). Es gibt ein altes ACM-Papier über die Durchführung von In-Place-Transpositionen ( http://doi.acm.org/10.1145/355719.355729 ), aber ihr Beispielcode ist hässliches, mit Goto beladenes FORTRAN.

Nachtrag:

http://doi.acm.org/10.1145/355611.355612 ist ein weiterer, vermeintlich besserer Algorithmus für die Transposition an Ort und Stelle.

9voto

Kevin Berridge Punkte 6132

Nick's Antwort würde auch für ein NxM-Array mit nur einer kleinen Änderung funktionieren (im Gegensatz zu einem NxN-Array).

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

Man kann sich das so vorstellen, dass Sie den Mittelpunkt der Achse (0,0) von der linken oberen Ecke in die rechte obere Ecke verschoben haben. Sie transponieren einfach von einer zur anderen.

7voto

user2793692 Punkte 1

Zeit - O(N), Raum - 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;
        }
    }
}

7voto

Kapil Punkte 192

Eine gängige Methode zum Drehen eines 2D-Arrays im oder gegen den Uhrzeigersinn.

  • im Uhrzeigersinn drehen

    • zuerst von oben nach unten umkehren, dann die Symmetrie vertauschen

      1 2 3     7 8 9     7 4 1
      4 5 6  => 4 5 6  => 8 5 2
      7 8 9     1 2 3     9 6 3

    void rotate(vector<vector<int> > &matrix) { reverse(matrix.begin(), matrix.end()); for (int i = 0; i < matrix.size(); ++i) { for (int j = i + 1; j < matrix[i].size(); ++j) swap(matrix[i][j], matrix[j][i]); } }

  • gegen den Uhrzeigersinn rotieren

    • zuerst von links nach rechts umkehren, dann die Symmetrie vertauschen

      1 2 3     3 2 1     3 6 9
      4 5 6  => 6 5 4  => 2 5 8
      7 8 9     9 8 7     1 4 7

    void anti_rotate(vector<vector<int> > &matrix) { for (auto vi : matrix) reverse(vi.begin(), vi.end()); for (int i = 0; i < matrix.size(); ++i) { for (int j = i + 1; j < matrix[i].size(); ++j) swap(matrix[i][j], matrix[j][i]); } }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X