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

C++で行列を螺旋状に出力する方法(スパイラルマトリックス)

スパイラルマトリックスとは

行列(マトリックス)の要素を螺旋状に出力する問題を考えてみましょう。まず最初の行全体を左から右へ出力し、次に最終列を上から下へ、続いて最終行を右から左へ、さらに最初の列を下から上へと出力します。この一連の流れを内側へ向かって繰り返すことで、行列の要素を螺旋状に表示できます。

例として、次のような3行6列の行列を用意しました。

123456
789101112
131415161718

この行列を螺旋状に出力すると、結果は次のようになります。

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

アルゴリズムの手順

この問題は、以下の手順で解くことができます。

  • 現在の行を表す currRow と現在の列を表す currCol を 0 で初期化する

  • currRowcurrCol が行列の範囲内である間、以下を繰り返す

    • 上端の行を左から右へ出力する(currCol から n-1 まで)

    • currRow を 1 増やして次の行へ移動する

    • 右端の列を上から下へ出力する(currRow から m-1 まで)

    • n を 1 減らし、新しい右端の列を設定する

    • currRowm 未満の場合、下端の行を右から左へ出力し、m を 1 減らす

    • currColn 未満の場合、左端の列を下から上へ出力し、currCol を 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]
[7,8,9,10,11,12]
[13,14,15,16,17,18]]

出力

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

このアルゴリズムの計算量は O(m×n) で、行列の全要素をちょうど1回ずつ訪問するため、非常に効率的です。正方行列だけでなく、行数と列数が異なる長方形の行列にも対応できる点もポイントです。

  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