37

我认为这个问题有一个简单的解决方案,几个 for 循环和一些花哨的计数器,但显然它相当复杂。

所以我的问题是,你将如何(用 C 语言)编写对角线中方阵的函数遍历。

例子:

1  2  3
4  5  6
7  8  9

必须按以下顺序遍历:

[1],[2,4],[3,5,7],[6,8],[9]

上面的每个条带都用方括号括起来。要求之一是能够区分条带。这意味着您知道何时开始新的条带。这是因为我必须为片段中的每个项目调用另一个函数,然后在新片段开始之前调用。因此,没有代码重复的解决方案是理想的。

4

17 回答 17

66

这是你可以使用的东西。只需将 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;
}

输出:

Slice 0: 1
Slice 1: 2 4
Slice 2: 3 5 7
Slice 3: 6 8
Slice 4: 9
于 2009-11-22T16:53:29.140 回答
46

我会像这样移动行:

1  2  3  x  x
x  4  5  6  x
x  x  7  8  9

并且只是迭代列。这实际上可以在没有物理移位的情况下完成。

于 2009-11-22T17:18:23.537 回答
22

让我们看看矩阵元素是如何索引的。

(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)  

现在,让我们看一下条纹:

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)

如果你仔细观察,你会注意到一件事。每个条带中每个矩阵元素的索引总和是恒定的。所以,这是执行此操作的代码。

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();
    }
}

它不是最快的算法(does(rows * cols * (rows+cols-2)) 操作),但它背后的逻辑非常简单。

于 2012-02-21T17:07:04.217 回答
5

我在这里找到了这个:在对角线中遍历矩形矩阵

#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;
}

现在我把其他两个方向留给你^^(只有当订单真的很重要时才重要)。

这个算法很让人费解,即使你认为你知道它是如何工作的,它仍然会咬你的屁股。但是我认为它非常漂亮,因为它确实像您期望的那样在矩阵中移动。如果有人对算法有更多了解,例如名称,我很感兴趣,所以我可以看看我在这里所做的是否真的有意义,也许有更好的解决方案。

于 2015-10-27T10:10:07.577 回答
4

我认为这可以成为任何类型矩阵的解决方案。

#include <stdio.h>

#define M 3
#define N 4

main(){
         int a[M][N] = {{1, 2, 3, 4}, 
                        {5, 6, 7, 8}, 
                        {9,10,11,12}};

         int i, j, t;
         for( t = 0; t<M+N; ++t)
              for( i=t, j=0; i>=0 ; --i, ++j)
                     if( (i<M) && (j<N) )
                             printf("%d ", a[i][j]);
         return 0;
}
于 2016-07-19T16:29:54.783 回答
3

我认为这个问题有一个简单的解决方案,几个 for 循环和一些花哨的计数器

恰恰。

需要注意的重要一点是,如果您给每个项目一个索引 ( i , j ),那么同一对角线上的项目具有相同的值j + n –<em>i,其中n是矩阵的宽度。因此,如果您以通常的方式迭代矩阵(即在ij上的嵌套循环),那么您可以跟踪以上述方式寻址的数组中的对角线。

于 2009-11-22T16:44:52.807 回答
2

// 此算法适用于所有大小的矩阵。;)

    int x = 0;
    int y = 0;        
    int sub_x;
    int sub_y;

    while (true) {

        sub_x = x;
        sub_y = y;

        while (sub_x >= 0 && sub_y < y_axis.size()) {

            this.print(sub_x, sub_y);
            sub_x--;
            sub_y++;

        }

        if (x < x_axis.size() - 1) {

            x++;

        } else if (y < y_axis.size() - 1) {

            y++;

        } else {

            break;

        }

    }
于 2010-06-25T23:40:31.207 回答
1

关键是迭代第一行中的每个项目,然后沿着对角线向下移动。然后迭代最后一列中的每个项目(没有第一个,我们在上一步中逐步完成),然后沿着对角线向下。

这是假定矩阵是方阵的源代码(未经测试,从工作 python 代码翻译):

#define N 10
void diag_step(int[][] matrix) {
    for (int i = 0; i < N; i++) {
        int j = 0;
        int k = i;
        printf("starting a strip\n");
        while (j < N && i >= 0) {
            printf("%d ", matrix[j][k]);
            k--;
            j++;
        }
        printf("\n");
    }

    for (int i = 1; i < N; i++) {
        int j = N-1;
        int k = i;
        printf("starting a strip\n");
        while (j >= 0 && k < N) {
            printf("%d ", matrix[k][j]);
            k++;
            j--;
        }
        printf("\n");
    }   
}   
于 2009-11-22T16:43:28.427 回答
1

伪代码:

N = 2 // or whatever the size of the [square] matrix
for x = 0 to N
  strip = []
  y = 0
  repeat
     strip.add(Matrix(x,y))
     x -= 1
     y -= 1
  until x < 0
  // here to print the strip or do some' with it

// And yes, Oops, I had missed it... 
// the 2nd half of the matrix...
for y = 1 to N    // Yes, start at 1 not 0, since main diagonal is done.
   strip = []
   x = N
   repeat
      strip.add(Matrix(x,y))
      x -= 1
      y += 1
   until x < 0
  // here to print the strip or do some' with it

(假设 x 索引行,y 索引列,如果矩阵以相反的方式索引,则反转这两者)

于 2009-11-22T16:44:28.317 回答
1

以防万一有人需要在 python 中执行此操作,使用 numpy 非常容易:

#M is a square numpy array    
for i in range(-M.shape[0]+1, M.shape[0]):
    print M.diagonal(offset=i)
于 2012-05-31T19:01:06.840 回答
1
public void printMatrix(int[][] matrix) {
    int m = matrix.length, n = matrix[0].length;
    for (int i = 0; i < m + n - 1; i++) {
         int start_row = i < m ? i : m - 1;
         int start_col = i < m ? 0 : i - m + 1;
         while (start_row >= 0 && start_col < n) {
               System.out.print(matrix[start_row--][start_col++]);
         }
         System.out.println("\n")
     }
}
于 2017-01-31T22:43:45.403 回答
0

您必须将矩阵分成上下部分,并分别迭代它们中的每一个,先半行,再先另一列。让我们假设矩阵是 n*n,存储在一个向量中,行在前,零基数,循环对最后一个元素是专有的。

for i in 0:n
    for j in 0:i +1
        A[i + j*(n-2)]

the other half can be done in a similar way, starting with:
for j in 1:n
    for i in 0:n-j
        ... each step is i*(n-2) ...
于 2009-11-22T17:11:44.723 回答
0

我可能会做这样的事情(提前为任何索引错误道歉,还没有调试过):

// Operation to be performed on each slice:
void doSomething(const int lengthOfSlice,
                 elementType *slice,
                 const int stride) {
    for (int i=0; i<lengthOfSlice; ++i) {
        elementType element = slice[i*stride];
        // Operate on element ...
    }
}

void operateOnSlices(const int n, elementType *A) {
    // distance between consecutive elements of a slice in memory:
    const int stride = n - 1;

    // Operate on slices that begin with entries in the top row of the matrix
    for (int column = 0; column < n; ++column)
        doSomething(column + 1, &A[column], stride);

    // Operate on slices that begin with entries in the right column of the matrix
    for (int row = 1; row < n; ++row)
        doSomething(n - row, &A[n*row + (n-1)], stride);
}
于 2009-11-22T17:31:41.260 回答
0
static int[][] arr = {{ 1, 2, 3, 4},
                      { 5, 6, 7, 8},
                      { 9,10,11,12},
                      {13,14,15,16} };

public static void main(String[] args) {
    for (int i = 0; i < arr.length; i++) {
        for (int j = 0; j < i+1; j++) {
            System.out.print(arr[j][i-j]);
            System.out.print(",");
        }
        System.out.println();
    }

    for (int i = 1; i < arr.length; i++) {
        for (int j = 0; j < arr.length-i; j++) {
            System.out.print(arr[i+j][arr.length-j-1]);
            System.out.print(",");
        }
        System.out.println();
    }
}
于 2013-02-27T22:39:13.843 回答
0

一个更简单的实现:

//Assuming arr as ur array and numRows and numCols as what they say.
int arr[numRows][numCols];
for(int i=0;i<numCols;i++) {
    printf("Slice %d:",i);
    for(int j=0,k=i; j<numRows && k>=0; j++,k--)
    printf("%d\t",arr[j][k]);
}
于 2015-02-17T09:46:19.897 回答
0
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

int main() 
{
    int N = 0;
    cin >> N;

    vector<vector<int>> m(N, vector<int>(N, 0));

    for (int i = 0; i < N; ++i)
    {
        for (int j = 0; j < N; ++j)
        {
            cin >> m[i][j];
        }
    }

    for (int i = 1; i < N << 1; ++i)
    {
        for (int j = 0; j < i; ++j)
        {
            if (j < N && i - j - 1 < N)
            {                          
               cout << m[j][i - j - 1];
            }
        }
        cout << endl;
    }
    return 0;
}
于 2015-09-27T08:11:15.703 回答
0

一个简单的python解决方案

from collections import defaultdict

def getDiagonals(matrix):
    n, m = len(matrix), len(matrix[0])
    diagonals = defaultdict(list)

    for i in range(n):
        for j in range(m):
            diagonals[i+j].append(matrix[i][j])

    return list(diagonals.values())

matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

assert getDiagonals(matrix) == [[1], [2, 4], [3, 5, 7], [6, 8], [9]]
于 2021-02-11T19:31:50.473 回答