我在这里找到了这个:在对角线中遍历矩形矩阵
#include <stdio.h>
int main()
{
int x[3][4] = { 1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12};
int m = 3;
int n = 4;
for (int slice = 0; slice < m + n - 1; ++slice) {
printf("Slice %d: ", slice);
int z1 = slice < n ? 0 : slice - n + 1;
int z2 = slice < m ? 0 : slice - m + 1;
for (int j = slice - z2; j >= z1; --j) {
printf("%d ", x[j][slice - j]);
}
printf("\n");
}
return 0;
}
输出:
Slice 0: 1
Slice 1: 5 2
Slice 2: 9 6 3
Slice 3: 10 7 4
Slice 4: 11 8
Slice 5: 12
我发现这是一种非常优雅的方法,因为它只需要存储 2 个附加变量(z1 和 z2)的内存,这些变量基本上保存了有关每个切片长度的信息。外部循环通过切片编号 ( slice
) 移动,然后内部循环通过索引移动通过每个切片:slice - z1 - z2
。然后您需要的所有其他信息算法从哪里开始以及它如何在矩阵中移动。在前面的示例中,它将首先向下移动矩阵,然后在到达底部后向右移动: (0,0) -> (1,0) -> (2,0) -> (2,1) - > (2,2) -> (2,3)。这种模式再次被变量 z1 和 z2 捕获。行与slice
数字一起递增,直到它到达底部,然后z2
将开始递增,这可用于将行索引保持在其位置:slice - z2
. 每个切片的长度通过以下方式知道:slice - z1 - z2
,执行以下操作:((slice - z2) - (slice - z1 -z2)
减去算法以升序移动 m--,n++)结果z1
是内部循环的停止标准。仅保留列索引,这是从 j 到达底部后为常数这一事实方便地继承的,之后列索引开始增加。
前面的算法仅从左上角 (0,0) 开始按升序从左到右移动。当我需要这个算法时,我还需要从左下角(m,n)开始按降序搜索矩阵。因为我被算法迷住了,所以我决定深入研究并调整它:
- 切片长度再次通过以下方式得知:
slice -z1 - z2
- 切片的起始位置是:(2,0) -> (1,0) -> (0,0) -> (0,1) -> (0,2) -> (0,3)
- 每个切片的移动是 m++ 和 n++
我发现将其描述如下非常有用:
- slice=0 z1=0 z2=0 (2,0) (列索引= rowindex - 2)
- slice=1 z1=0 z2=0 (1,0) (2,1) (列索引= rowindex - 1)
- slice=2 z1=0 z2=0 (0,0) (1,1) (2,2) (列索引= rowindex + 0)
- slice=3 z1=0 z2=1 (0,1) (1,2) (2,3) (列索引= rowindex + 1)
- slice=4 z1=1 z2=2 (0,2) (1,3) (列索引= rowindex + 2)
- slice=5 z1=2 z2=3 (0,3) (列索引= rowindex + 3)
推导以下内容:(j = (m-1) - slice + z2
使用 j++)使用切片长度的表达式来制作停止标准:((m-1) - slice + z2)+(slice -z2 - z1)
结果为:(m-1) - z1
我们现在有了内循环的参数:for (int j = (m-1) - slice + z2; j < (m-1) - z1; j++)
行索引由 j 知道,并且我们再次知道列索引仅在 j 开始保持不变时才开始递增,因此在表达式中再次包含 j 并不是一个坏主意。j - (slice - m +1)
从上述总和之间的差异中,我注意到差异总是等于从左下角开始看起来如下:
#include <stdio.h>
int main()
{
int x[3][4] = { 1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12};
int m = 3;
int n = 4;
for (int slice = 0; slice < m + n - 1; ++slice) {
printf("Slice %d: ", slice);
int z1 = slice < n ? 0 : slice - n + 1;
int z2 = slice < m ? 0 : slice - m + 1;
for (int j = (m-1) - slice + z2; j <= (m-1) - z1; j++) {
printf("%d ", x[j][j+(slice-m+1)]);
}
printf("\n");
}
return 0;
}
现在我把其他两个方向留给你^^(只有当订单真的很重要时才重要)。
这个算法很让人费解,即使你认为你知道它是如何工作的,它仍然会咬你的屁股。但是我认为它非常漂亮,因为它确实像您期望的那样在矩阵中移动。如果有人对算法有更多了解,例如名称,我很感兴趣,所以我可以看看我在这里所做的是否真的有意义,也许有更好的解决方案。