Comme je l'ai dit dans mon message précédent, voici du code en C# qui implémente une rotation de matrice O(1) pour une matrice de n'importe quelle taille. Pour des raisons de brièveté et de lisibilité, il n'y a pas de contrôle d'erreur ni de contrôle de plage. Le code :
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;
}
D'accord, je vais lever la main, il n'apporte en fait aucune modification au tableau d'origine lors de la rotation. Mais, dans un système OO, cela n'a pas d'importance tant que l'objet semble avoir été tourné pour les clients de la classe. Pour l'instant, la classe Matrix utilise des références aux données du tableau d'origine, donc changer une valeur de m1 changera aussi m2 et m3. Une petite modification du constructeur pour créer un nouveau tableau et y copier les valeurs permettra de résoudre ce problème.
117 votes
Comment pouvez-vous vous en sortir avec moins de n^2 ? Tous les éléments doivent être lus et fixés, et il y a n^2 éléments.
1 votes
Voir aussi stackoverflow.com/questions/848025/rotating-bitmaps-in-code
0 votes
L'intérêt de poser cette question (dans l'histoire de Raymond) était juste de s'assurer que le candidat avait un certain nombre de capacités de base. La solution n^2 est très bien.
9 votes
Quel est votre n ? Vous ne dites pas si le tableau 2D est carré (il ne l'est pas dans le cas général ! Par exemple, un vecteur est une matrice avec une dimension de 1), mais vous semblez impliquer que n est la largeur et la hauteur, et qu'il y a donc n² éléments. Il serait plus logique que n soit le nombre d'éléments, avec n=w×h.
0 votes
Je suis d'accord avec niXar. Ce n'est pas parce que N a une forte corrélation avec le carré d'une autre valeur que la solution est N^2.
0 votes
Je n'ai pas le temps de l'écrire, mais la manière préférée d'effectuer des rotations est d'utiliser des quaternions.
0 votes
Il serait plus difficile si sa dimension est
NxM
au lieu deNxN
.0 votes
Notez que pour les tableaux de grande taille, les manques de cache peuvent être problématiques, vous voudrez donc utiliser le tuilage comme suggéré dans la réponse à la question suivante stackoverflow.com/questions/848025/rotating-bitmaps-in-code . En procédant ainsi, vous vous retrouverez avec une boucle quadruplement imbriquée.
1 votes
Voici un moyen rapide de le faire : stockez les indices de ligne et de colonne (disons i et j). La transposition prend un temps constant (il suffit de permuter les indices :). Vous pouvez faire la même chose avec les rotations (jouer avec les indices).
4 votes
Au cas où n^2 ne serait pas réalisable. Vous pouvez créer une interface qui accède à chaque élément. Puis, étant donné (i, j), appliquer une rotation à (i, j), accéder à l'élément ayant subi une rotation et retourner. Ce n'est peut-être pas la meilleure solution, mais elle fonctionne.
1 votes
Je pense que vous pouvez toujours le faire avec moins de N^2. Cependant, une structure de données plus compliquée est nécessaire. Peut-être un type de liste doublement liée ?
0 votes
@erikkallen pourrait-il être compressé ?
0 votes
Je l'ai fait avec une seule boucle : stackoverflow.com/a/61812224/996926