37

I thought this problem had a trivial solution, couple of for loops and some fancy counters, but apparently it is rather more complicated.

So my question is, how would you write (in C) a function traversal of a square matrix in diagonal strips.

Example:

1  2  3
4  5  6
7  8  9

Would have to be traversed in the following order:

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

Each strip above is enclosed by square brackets. One of the requirements is being able to distinguish between strips. Meaning that you know when you're starting a new strip. This because there is another function that I must call for each item in a strip and then before the beginning of a new strip. Thus a solution without code duplication is ideal.

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) を移動し、内側のループは index: の各スライスを移動します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++ です

私はそれを次のように描写することが非常に有用であることを発見しました:

  • スライス=0 z1=0 z2=0 (2,0) (列インデックス= 行インデックス - 2)
  • スライス=1 z1=0 z2=0 (1,0) (2,1) (列インデックス= 行インデックス - 1)
  • スライス=2 z1=0 z2=0 (0,0) (1,1) (2,2) (列インデックス= 行インデックス + 0)
  • スライス=3 z1=0 z2=1 (0,1) (1,2) (2,3) (列インデックス= 行インデックス + 1)
  • スライス=4 z1=1 z2=2 (0,2) (1,3) (列インデックス= 行インデックス + 2)
  • スライス=5 z1=2 z2=3 (0,3) (列インデックス= 行インデックス + 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;
}

残りの 2 つの方向性はあなたに任せます ^^ (これは順序が実際に重要な場合にのみ重要です)。

このアルゴリズムは非常に頭を悩ませるものであり、その仕組みを知っていると思っていても、お尻を噛まれる可能性があります。しかし、あなたが期待するように文字通りマトリックスを移動するので、それは非常に美しいと思います. たとえば名前など、アルゴリズムについて誰かがもっと知っているかどうかに興味があるので、ここで行ったことが実際に意味があるかどうか、さらに良い解決策があるかどうかを調べることができます。

于 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 は列にインデックスを付けると仮定します。行列が逆にインデックス付けされている場合は、これら 2 つを逆にします)

于 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 に答える
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

はるかに簡単な実装:

//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

私はおそらく次のようなことをするでしょう(インデックスエラーについては事前にお詫びします。これはデバッグしていません):

// 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
#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 に答える