web-dev-qa-db-ja.com

斜めストリップのトラバースマトリックス

この問題には、2つのforループといくつかの派手なカウンターのような簡単な解決策があると思いましたが、明らかにそれはかなり複雑です。

だから私の質問は、正方行列の関数トラバーサルを対角ストリップで(Cで)どのように書くのですか?.

例:

1  2  3
4  5  6
7  8  9

次の順序でトラバースする必要があります。

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

上記の各ストリップは角括弧で囲まれています。要件の1つは、ストリップを区別できることです。新しいストリップを始めるときに知っていることを意味します。これは、ストリップ内の各項目に対して、新しいストリップの開始前に呼び出す必要がある別の関数があるためです。したがって、コードの重複のないソリューションが理想的です。

30
alyx

これがあなたが使えるものです。 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
61
Mark Byers

行を次のようにシフトします。

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

そして、列を繰り返すだけです。これは実際には、物理​​的なシフトなしで実行できます。

39
Kugel

行列要素がどのようにインデックス付けされるかを見てみましょう。

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

よく見ると、1つのことに気づくでしょう。各ストライプの各行列要素のインデックスの合計は一定です。これを行うコードは次のとおりです。

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))演算)ではありませんが、その背後にあるロジックは非常に単純です。

21
ioreskovic

私はここでこれを見つけました: 斜めのストリップのトラバース長方形行列

_#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)(列インデックス=行インデックス-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)(列インデックス=行インデックス+ 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;
}
_

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

このアルゴリズムは、それがどのように機能するかを知っていると思っていても、それでもなお尻に噛み付く可能性があります。しかし、文字通りマトリックス内を移動するので、とても美しいと思います。誰かがアルゴリズムなどについてもっと知っていれば興味があります。たとえば、ここで行ったことが実際に理にかなっているか、もっと良い解決策があるかどうかを調べることができます。

4
Sjonnie

これはあらゆるタイプのマトリックスの解決策になると思います。

#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
tech.samar

この問題は簡単な解決策であると思いました、いくつかのforループといくつかの派手なカウンター

正確に。

注意すべき重要な点は、各アイテムにインデックス(ij)を与えると、同じ対角線上のアイテムは同じ値jを持つということです。 = + ni、ここでnはマトリックスの幅です。したがって、通常の方法で行列を反復処理する場合(つまり、ネストされたループiおよびj)を使用すると、配列で対角線を追跡できます。上記の方法。

3
Konrad Rudolph

//このアルゴリズムは、すべてのサイズの行列に対して機能します。 ;)

    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;

        }

    }
2
Johnyk11

重要なのは、最初の行のすべてのアイテムを反復処理し、そこから対角線を下っていくことです。次に、最後の列のすべてのアイテム(前のステップで最初に実行したものを除く)を繰り返してから、その対角線を下っていきます。

これは、マトリックスが正方マトリックスであると想定するソースコードです(テストされていない、作業から変換python code):

#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");
    }   
}   
1
abyx

疑似コード:

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つを逆にします)

1
mjv

誰かがこれをPythonで行う必要がある場合に備えて、numpyを使用すると非常に簡単です:

#M is a square numpy array    
for i in range(-M.shape[0]+1, M.shape[0]):
    print M.diagonal(offset=i)
1
Oriol Nieto
#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;
}
0
user5380950

マトリックスを上部と下部に分割し、それぞれを別々に、最初に半分の行、最初に別の列で繰り返す必要があります。行列が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) ...
0
Anycorn

はるかに簡単な実装:

//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]);
}
0
SinnerShanky

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

// 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);
}
0
Stephen Canon
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();
    }
}
0
engin
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")
     }
}
0
TankZhuang