我有一项任务是旋转具有n列和m行的2D矩阵R`times 。旋转应沿逆时针方向旋转。
我的代码存在以下问题:
StepValuesOperation
方法错误地从矩阵中获取或设置了值。我已经打破了头脑,找出问题所在。关于代码:
InitializeParams
方法随机初始化矩阵大小,其值和旋转计数; StepValuesOperation
方法得到当前迭代的值数组; rotCount
操作得到mod
。 然后按RorateValues
方法旋转值,并按StepValuesOperation
private static void Main(string[] args)
{
int m, r, n;
long[,] matrix;
InitializeParams(out n, out m, out r, out matrix);
Console.WriteLine("Rotation times: " + r);
Console.WriteLine("Input matrix:");
PrintMatrix(matrix);
Console.WriteLine();
int deep = Math.Min(m, n) / 2;
for (int step = 0; step < deep; step++)
{
List<long> oldArr = new List<long>((n + m) * 2);
StepValuesOperation(false, step, oldArr, matrix);
int perim = oldArr.Count;
int rotCount = perim < r ? r % perim : r;
if (rotCount != 0 && rotCount != perim)
{
long[] newArr = new long[perim];
Console.WriteLine($"Rest rotation count {rotCount} from {r} with perimeter {perim}");
Console.WriteLine(string.Join(", ", oldArr));
RorateValues(rotCount, newArr, oldArr);
Console.WriteLine(string.Join(", ", newArr));
StepValuesOperation(true, step, newArr, matrix);
}
Console.WriteLine();
}
Console.WriteLine();
Console.WriteLine("Output matrix:");
PrintMatrix(matrix);
Console.ReadLine();
}
private static void RorateValues(int rotCount, IList<long> newArr, IList<long> oldArr)
{
int perim = oldArr.Count;
for (int i = 0; i < perim; i++)
{
int pos = i + rotCount;
if (pos >= perim)
{
pos -= perim;
}
newArr[pos] = oldArr[i];
}
}
private static void InitializeParams(out int n, out int m, out int r, out long[,] matrix)
{
Random rand = new Random();
n = 4;//rand.Next(2, 7) * 2;
m = 6;//rand.Next(1, 5) * 2;
r = rand.Next(1, 10000);
matrix = new long[n, m];
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
matrix[i, j] = rand.Next(i + j, i + j + n * 10);
}
}
}
private static void StepValuesOperation(bool initialized, int step, IList<long> arr, long[,] matrix)
{
int sizeI = matrix.GetLength(0) - step;
int sizeJ = matrix.GetLength(1) - step;
int pos = 0;
for (int i = step; i < sizeI; i++, pos++)
{
if (!initialized)
arr.Add(matrix[i, step]);
else
matrix[i, step] = arr[pos];
}
for (int j = step; j < sizeJ; j++, pos++)
{
if (!initialized)
arr.Add(matrix[sizeI - 1, j]);
else
matrix[sizeI - 1, j] = arr[pos];
}
for (int i = sizeI - 1; i > step; i--, pos++)
{
if (!initialized)
arr.Add(matrix[i, sizeJ - 1]);
else
matrix[i, sizeJ - 1] = arr[pos];
}
for (int j = sizeJ - 1; j > step; j--, pos++)
{
if (!initialized)
arr.Add(matrix[step, j]);
else
matrix[step, j] = arr[pos];
}
}
private static void PrintMatrix(long[,] matrix)
{
int n = matrix.GetLength(0);
int m = matrix.GetLength(1);
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
Console.Write(matrix[i, j] + " ");
Console.WriteLine();
}
}
我的错误输出:
轮换时间:9402
输入矩阵:
29 3 24 9 39 28
9 38 31 20 24 44
27 27 38 31 10 37
32 15 25 40 40 42
输出矩阵:
44 37 42 42 40 40
28 20 24 10 10 25
39 38 27 27 31 15
24 3 29 9 27 32
答案 0 :(得分:1)
是的,轮换可以就地完成。我不是 C#程序员,所以我坚持 C ++ 语法非常接近。
我会创建旋转矩形周长的功能
可以使用单个临时值(与 jackmott 建议完全相同)来完成。像这样的东西:
void matrix_rect_ccw(int **a,int x0,int y0,int xs,int ys)
{
int x,y,xx,yy,x1,y1,a0;
// prepare constants
x1=x0+xs-1;
y1=y0+ys-1;
// rotate CCW
a0=a[x0][y0]; // store first element to temp
x=x0; y=y0; // destination
xx=x; yy=y; // source
for (xx++;x<x1;x++,xx++) a[x][y]=a[xx][yy]; xx--;
for (yy++;y<y1;y++,yy++) a[x][y]=a[xx][yy]; yy--;
for (xx--;x>x0;x--,xx--) a[x][y]=a[xx][yy]; xx++;
for (yy--;y>y0;y--,yy--) a[x][y]=a[xx][yy]; yy++;
a[x0][y0+1]=a0; // restore last element from temp
}
其中x0,y0
是矩形的左上角,xs,ys
是其大小。 a[][]
是矩阵。如果矩形完全位于...
要进行调试,您可以使用增加索引来旋转填充循环,例如:
int i=0;
for (xx++;x<x1;x++,xx++,i++) a[x][y]=i; xx--;
for (yy++;y<y1;y++,yy++,i++) a[x][y]=i; yy--;
for (xx--;x>x0;x--,xx--,i++) a[x][y]=i; xx++;
for (yy--;y>y0;y--,yy--,i++) a[x][y]=i; yy++;
或:
int i=0;
for (xx++;x<x1;x++,xx++,i++) a[xx][yy]=i; xx--;
for (yy++;y<y1;y++,yy++,i++) a[xx][yy]=i; yy--;
for (xx--;x>x0;x--,xx--,i++) a[xx][yy]=i; xx++;
for (yy--;y>y0;y--,yy--,i++) a[xx][yy]=i; yy++;
因此,您可以检查迭代是否以正确的顺序通过正确的元素。这是(x,y)
调用所有循环的结果:
0 1 2 3 4
13 0 1 2 5
12 5 4 3 6
11 10 9 8 7
这是(xx,yy)
案例:
13 0 1 2 3
12 5 0 1 4
11 4 3 2 5
10 9 8 7 6
执行for
循环以旋转整个矩阵
只需为所有循环调用#1 的旋转。还有整整step
次。像这样:
void matrix_ccw(int **a,int xs,int ys,int step)
{
int i,j,n;
// smallest size / 2 ... number of loops to rotate
n=xs; if (n<ys) n=ys; n/=2;
for (j=0;j<step;j++)
for (i=0;i<n;i++)
matrix_rect_ccw(a,i,i,xs-i-i,ys-i-i);
}
只需更改#1 中的for循环顺序,即可单独处理CW / CCW。您还应该将步长绑定到模数循环大小。如果步长较大,则循环大小的一半然后将其转换为反向旋转以加速该过程。这是我测试的输入矩阵:
11 12 13 14 15
21 22 23 24 25
31 32 33 34 35
41 42 43 44 45
这在 CCW 方向上由step=1
轮换:
12 13 14 15 25
11 23 24 34 35
21 22 32 33 45
31 41 42 43 44
您还应该处理无效的矩阵大小以便轮换,以避免在将来使用时出现混淆......
<强> [注释] 强>
旋转也可以在没有步骤循环整个事件的情况下通过直接复制step
偏移来完成,但为此你需要存储a0[step]
值而不是单一的值使这一点复杂化。
答案 1 :(得分:0)
我想知道你是否可以通过将外部点表示为一个循环链接列表而将内部点表示为另一个来简化它。然后使用单个临时变量将它们旋转到位变得非常容易。如果性能是一个问题,你可以为每个使用一维数组,只需处理开始和结束时的边缘情况。
编辑 - 看起来算法必须更加通用,这意味着“n”循环链接列表,这可能不是更简单。