aly*_*lyx 31 c algorithm traversal matrix
我认为这个问题有一个简单的解决方案,几个for循环和一些花哨的计数器,但显然它更复杂.
所以我的问题是,你如何编写(在C中)对角线条中方形矩阵的函数遍历.
例:
1 2 3
4 5 6
7 8 9
Run Code Online (Sandbox Code Playgroud)
必须按以下顺序遍历:
[1],[2,4],[3,5,7],[6,8],[9]
Run Code Online (Sandbox Code Playgroud)
上面的每个条带都用方括号括起来.其中一个要求是能够区分条带.这意味着你知道什么时候开始新的条带.这是因为我必须为条带中的每个项目调用另一个函数,然后在新条带的开头之前调用.因此,没有代码重复的解决方案是理想的.
Mar*_*ers 62
这是你可以使用的东西.只需将printfs替换为您实际想要做的事情.
#include <stdio.h>
int main()
{
int x[3][3] = {1, 2, 3,
4, 5, 6,
7, 8, 9};
int n = 3;
for (int slice = 0; slice < 2 * n - 1; ++slice) {
printf("Slice %d: ", slice);
int z = (slice < n) ? 0 : slice - n + 1;
for (int j = z; j <= slice - z; ++j) {
printf("%d ", x[j][slice - j]);
}
printf("\n");
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
Slice 0: 1
Slice 1: 2 4
Slice 2: 3 5 7
Slice 3: 6 8
Slice 4: 9
Run Code Online (Sandbox Code Playgroud)
Kug*_*gel 41
我会像这样移动行:
1 2 3 x x
x 4 5 6 x
x x 7 8 9
Run Code Online (Sandbox Code Playgroud)
只需迭代列.实际上,这可以在没有物理移位的情
ior*_*vic 21
我们来看看矩阵元素是如何编入索引的.
(0,0) (0,1) (0,2) (0,3) (0,4)
(1,0) (1,1) (1,2) (1,3) (1,4)
(2,0) (2,1) (2,2) (2,3) (2,4)
Run Code Online (Sandbox Code Playgroud)
现在,让我们来看看条纹:
Stripe 1: (0,0)
Stripe 2: (0,1) (1,0)
Stripe 3: (0,2) (1,1) (2,0)
Stripe 4: (0,3) (1,2) (2,1)
Stripe 5: (0,4) (1,3) (2,2)
Stripe 6: (1,4) (2,3)
Stripe 7: (2,4)
Run Code Online (Sandbox Code Playgroud)
如果你仔细看看,你会注意到一件事.每个条带中每个矩阵元素的索引总和是恒定的.所以,这是执行此操作的代码.
public static void printSecondaryDiagonalOrder(int[][] matrix) {
int rows = matrix.length;
int cols = matrix[0].length;
int maxSum = rows + cols - 2;
for (int sum = 0; sum <= maxSum; sum++) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (i + j - sum == 0) {
System.out.print(matrix[i][j] + "\t");
}
}
}
System.out.println();
}
}
Run Code Online (Sandbox Code Playgroud)
它不是最快的算法(行(col*cols*(行+ cols-2))),但它背后的逻辑非常简单.
小智 5
我在这里找到了这个:Traverse Rectangular Matrix in Diagonal strips
#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;
}
Run Code Online (Sandbox Code Playgroud)
输出:
Slice 0: 1
Slice 1: 5 2
Slice 2: 9 6 3
Slice 3: 10 7 4
Slice 4: 11 8
Slice 5: 12
Run Code Online (Sandbox Code Playgroud)
我发现这是一种非常优雅的方法,因为它只需要 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我发现将其描述如下非常有用:
推导以下内容:(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),在其他一些情况下测试这个我相信这将适用于所有情况(我不是数学家;P)以及下降运动的算法从左下角开始如下所示:
#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;
}
Run Code Online (Sandbox Code Playgroud)
现在我把其他两个方向留给你 ^^(只有在顺序实际上很重要时才重要)。
这个算法非常令人费解,即使你认为你知道它是如何工作的,它仍然会咬你的屁股。但是我认为它非常漂亮,因为它确实像您期望的那样在矩阵中移动。如果有人对算法有更多了解,例如名称,我很感兴趣,所以我可以看看我在这里所做的是否真的有意义,也许有更好的解决方案。
| 归档时间: |
|
| 查看次数: |
37536 次 |
| 最近记录: |