我的一个学生问我这种带有C ++数组的作业。这对我来说似乎很有意思,所以,虽然我已经解决了这个问题,但我想与你分享我的解决方案并了解其他变体和意见。问题如下:
问题 给出2D动态二次矩阵(阵列)A(nxn)。需要将数组逆时针旋转90度,也就是说,旋转后A [1,1]字段应包含A [1,n]的值,A [1,n]字段应包含值A [N,N-]。 并且还需要在解决此问题时不要使用任何其他阵列。
我的解决方案
我告诉学生要做以下事情(将代表示意图):
我建议定义一个类,作为其成员,将具有2D数组。并定义一个操作,当用户请求 A [i,j] 时,该操作将返回 A [j,n + 1-i] 元素的引用。用两个词我建议为数组创建一个包装器,并通过包装器通过数组进行操作。
答案 0 :(得分:21)
维基百科有一篇关于in-place matrix transposition的文章。
考虑:
a b c
e f g
x y z
transpose:
a e x
b f y
c g z
rotated 90 deg CCW:
c g z
b f y
a e x
因此,在进行转置后,请反转行,您可以轻松地就地执行这些行。
答案 1 :(得分:5)
您可以使用“四向交换”和带有一些旋转魔法的嵌套循环(在纸上制作):
template <typename T>
void swap(T& a, T& b, T& c, T& d)
{
T x(a);
a = b;
b = c;
c = d;
d = x;
}
template <typename T, size_t dim>
void rotate(T (&matrix)[dim][dim])
{
const size_t d = dim-1;
for (size_t y = 0; y < dim/2; ++y)
{
for (size_t x = y; x < d-y; ++x)
{
swap(matrix[y ][x ],
matrix[x ][d-y],
matrix[d-y][d-x],
matrix[d-x][y ]);
}
}
}
测试程序:
template <typename T, size_t dim>
void print(T (&matrix)[dim][dim])
{
for (size_t y = 0; y < dim; ++y)
{
for (size_t x = 0; x < dim; ++x)
{
std::cout << matrix[y][x] << ' ';
}
std::cout << '\n';
}
}
int main()
{
int matrix[4][4] = {{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}};
rotate(matrix);
print(matrix);
}
输出:
4 8 12 16
3 7 11 15
2 6 10 14
1 5 9 13
现在你只需要将它从模板形式转换为动态形式;)
答案 2 :(得分:2)
嗯,这不是C ++而是Java。对不起,但这里是一个简单数组支持Matrix
内的递归算法:
public void rotateInPlaceRecursive() {
if( rowCount != colCount ) {
throw new IllegalStateException("Matrix must be square");
}
doRotateInPlaceRecursive(0);
}
public void doRotateInPlaceRecursive(int shrink) {
if( shrink == rowCount/2 ) {
return;
}
for (int col = shrink; col < colCount-shrink-1; col++) {
int row = shrink;
int top = tab[row][col];
int left = tab[rowCount-col-1][row];
int bottom = tab[rowCount-row-1][rowCount-col-1];
int right = tab[col][rowCount-row-1];
tab[row][col] = right;
tab[rowCount-col-1][row] = top;
tab[rowCount-row-1][rowCount-col-1] = left;
tab[col][rowCount-row-1] = bottom;
}
doRotateInPlaceRecursive(shrink+1);
}
---- TEST
@Test
public void testRotateInPlaceRecursive() {
// given
int N = 5;
Matrix matrix = new Matrix(N, N);
// when
int i=0;
for( int row = 0; row< N; row++ ) {
for( int col = 0; col< N; col++ ) {
matrix.set(row,col, i++ );
}
}
// then
matrix.rotateInPlaceRecursive();
i = 0;
for( int row = 0; row< N; row++ ) {
for( int col = 0; col< N; col++ ) {
assertEquals(i++,matrix.get(N-col-1,row));
}
}
}
答案 3 :(得分:2)
下面的示例是Java,可以很容易地用于C ++。在内存中旋转大型矩阵可能会消耗大量资源,尤其是当矩阵的值是复杂对象时。在这种情况下,使用函数重新计算索引可能更有效,这些函数会将它们重定向到旋转矩阵的元素而不进行实际旋转。
public class RotateArray {
public static char arr[][] = { { 'a', 'b', 'c','1' }, { 'd', 'e', 'f','2' }, { 'g', 'h', 'i','3' },{ 'j', 'k', 'l','4' } };
private static int imax = arr.length-1;
private static int jmax = arr[0].length-1;
public static void printArray() {
for (int i = 0; i <= imax; i++) {
for (int j = 0; j <= jmax; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.print("\n");
}
}
public static void printRotatedArray() {
for (int i = 0; i <= imax; i++) {
for (int j = 0; j <= jmax; j++) {
System.out.print(arr[getRotatedI(i,j)][getRotatedJ(i,j)] + " ");
}
System.out.print("\n");
}
}
public static int getRotatedI(int i,int j){
int ii = imax-j;
return ii;
}
public static int getRotatedJ(int i,int j){
int jj = i;
return jj;
}
public static void main(String[] args) {
System.out.println("Printing matrix");
printArray();
System.out.println("Printing rotated matrix");
printRotatedArray();
}
}
输出:
Printing matrix
a b c 1
d e f 2
g h i 3
j k l 4
Printing rotated matrix
j g d a
k h e b
l i f c
4 3 2 1
答案 4 :(得分:-1)
O(n ^ 2)时间和O(1)空间算法(没有任何变通方法和手帕的东西!)
旋转+90:
Transpose
Reverse each row
旋转-90:
Transpose
Reverse each column
旋转+180:
方法1:旋转+90两次
方法2:反转每一行,然后反转每一列
旋转-180:
方法1:旋转-90两次
方法2:反转每一列,然后反转每一行
方法3:因为它们相同而反转+180