プログラミング
 Computer >> コンピューター >  >> プログラミング >> プログラミング

マトリックスを螺旋状(スパイラル)に出力するアルゴリズム

このアルゴリズムは、2次元配列(マトリックス)の要素を螺旋状(スパイラル形式)に出力するために用いられます。処理の流れは以下の通りです。

まず最初の行を左から右へすべて出力し、続いて最後の列を上から下へ、次に最後の行を右から左へ、さらに最初の列を下から上へと出力します。この一連の操作を内側に向かって繰り返すことで、要素が渦巻き状に順番に出力されます。

このアルゴリズムの時間計算量は O(MN) です。ここで M は行数、N は列数を表します。

入力と出力

Input:
The matrix:
 1   2   3   4   5   6
 7   8   9  10  11  12
13  14  15  16  17  18

Output:
Contents of an array as the spiral form
1 2 3 4 5 6 12 18 17 16 15 14 13 7 8 9 10 11 15 16

アルゴリズム

dispSpiral(mat, m, n)

入力:マトリックス mat、行数 m、列数 n。

出力:マトリックスの全要素を螺旋状の順序で出力する。

Begin
    currRow := 0 かつ currCol := 0
    while currRow と currCol がマトリックスの範囲内である間、繰り返す
        for i を currCol から n-1 まで、繰り返す
            display mat[currRow, i]
        done

        currRow を 1 増やす
        for i を currRow から m-1 まで、繰り返す
            display mat[i, n-1]
        done

        n を 1 減らす
        if currRow < m ならば
            for i := n-1 から currCol まで減少させながら、繰り返す
                display mat[m-1, i]
            done
            m を 1 減らす
        if currCol < n ならば
            for i := m-1 から currRow まで減少させながら、繰り返す
                display mat[i, currCol]
            done
            currCol を 1 増やす
    done
End

アルゴリズムのポイント

  • currRow / currCol:現在の出力対象となっている外周の開始位置(行・列)を管理します。
  • m / n の更新:各行・各列を出力し終えるたびに範囲を狭めていくことで、すでに出力済みの外側の要素を二度と参照しないようにしています。
  • 範囲チェック:最後の行や最初の列を出力する前に条件判定を行うことで、1行のみ・1列のみの残りマトリックスでも重複出力を防ぎます。

C++による実装例

#include <iostream>
#define ROW 3
#define COL 6
using namespace std;

int array[ROW][COL] = {
    {1, 2, 3, 4, 5, 6},
    {7, 8, 9, 10, 11, 12},
    {13, 14, 15, 16, 17, 18}
};

void dispSpiral(int m, int n) {
    int i, currRow = 0, currCol = 0;
    while (currRow < ROW && currCol < COL) {
        for (i = currCol; i < n; i++) {          //最初の行をそのまま出力
            cout << array[currRow][i] << " ";
        }
        currRow++;                                //次の行へ移動

        for (i = currRow; i < m; ++i) {           //最後の列を出力
            cout << array[i][n-1] << " ";
        }

        n--;                                      //n-1列目を新たな最終列として設定

        if (currRow < m) {                        //currRowが範囲内なら最後の行を出力
            for (i = n-1; i >= currCol; --i) {
                cout << array[m-1][i] << " ";
            }
            m--;                                  //行の範囲を縮小
        }

        if (currCol < n) {                        //currColが範囲内なら最初の列を出力
            for (i = m-1; i >= currRow; --i) {
                cout << array[i][currCol] << " ";
            }
            currCol++;                            //列の開始位置を進める
        }
    }
}

int main() {
    dispSpiral(ROW, COL);
}

実行結果

1 2 3 4 5 6 12 18 17 16 15 14 13 7 8 9 10 11 15 16

このように、3×6 のマトリックスの要素が、外周から内側へ向かって螺旋状に正しく出力されていることが確認できます。

  1. C++で解くスパイラル行列 III:時計回りに全マスを訪問するアルゴリズム

    本記事では、R行C列の2次元グリッドを時計回りの渦巻き(スパイラル)状に巡回し、すべてのマスを訪問した順に座標を求める問題「スパイラル行列 III」をC++で解く方法を解説します。 問題の概要 R行C列の2次元グリッドを考えます。スタート地点は (r0, c0) で、最初は東向きに面しています。グリッドの北西の角は第1行・第1列に位置し、南東の角は最終行・最終列にあります。 私たちは時計回りの渦巻き状に歩きながら、グリッド内のすべてのマスを訪問します。途中でグリッドの境界外に出た場合でも、そのまま外側を歩き続け、後で再びグリッド内に戻ることがあります。 求めるのは、訪問した順番に並べたグリッド

  2. C++で2次元行列を反時計回りのスパイラル形式で出力する方法

    この記事では、2次元行列が与えられたときに、そのすべての要素を反時計回りのスパイラル形式で出力する方法を解説します。 反時計回りのスパイラル形式とは? 反時計回りのスパイラル形式とは、行列の左上の要素から開始し、最初に下方向へ進み、続いて右→上→左と方向を変えながら、渦巻き状に外側から内側へと要素をたどっていく走査方法です。 例として、次の4×4の行列を見てみましょう。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 この行列を反時計回りに走査すると、出力は「1 5 9 13 14 15 16 12 8 4 3 2 6 10