对角线条中的导线矩阵

时间:2009-11-22 16:35:36

标签: c algorithm matrix traversal

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

所以我的问题是,你怎么写(在C中)对角线条中方形矩阵的函数遍历。

示例:

1  2  3
4  5  6
7  8  9

必须按以下顺序遍历:

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

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

17 个答案:

答案 0 :(得分:61)

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

答案 1 :(得分:39)

我会像这样移动行:

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

只需迭代列。实际上,这可以在没有物理转移的情况下完成。

答案 2 :(得分: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)  

现在,让我们来看看条纹:

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

这不是最快的算法(行(col * cols *(行+ cols-2))),但它背后的逻辑非常简单。

答案 3 :(得分: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;
}

答案 4 :(得分:4)

我在这里找到了这个: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;
}

输出:

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) - &gt; (1,0) - &gt; (2,0) - &gt; (2,1) - &gt; (2,2) - &gt; (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) - &gt; (1,0) - &gt; (0,0) - &gt; (0,1) - &gt; (0,2) - &gt; (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),对其他一些情况进行测试我相信这将适用于所有情况(我不是数学家; 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;
}

现在我将另外两个方向留给你^^(这在订单实际上很重要时才重要)。

这个算法非常简单,即使你认为你知道它是如何工作的,它仍然可以咬你的屁股。但是我认为它非常漂亮,因为它可以像你期望的那样在矩阵中移动。我感兴趣的是,如果有人知道关于算法的更多信息,例如名称,那么我可以看看我在这里所做的事情是否真的有意义并且可能有更好的解决方案。

答案 5 :(得分:3)

  

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

正。

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

答案 6 :(得分: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;

        }

    }

答案 7 :(得分: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索引列,如果矩阵被反向索引则反转这两个)

答案 8 :(得分: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)

答案 9 :(得分: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");
    }   
}   

答案 10 :(得分: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);
}

答案 11 :(得分: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();
    }
}

答案 12 :(得分: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]);
}

答案 13 :(得分: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;
}

答案 14 :(得分: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) ...

答案 15 :(得分:0)

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")
     }
}

答案 16 :(得分: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]]