C++における二次元配列の実装と操作

二次元配列は、行と列の構造を持つデータ格納機構であり、C++では配列の配列として実現されます。この構造は行列的なデータ処理やゲーム開発、画像処理など、多次元データを扱う場面で広く利用されます。

宣言と初期化

二次元配列は、行数と列数を明示的に指定して宣言します。以下のように、静的サイズで宣言可能です:

int grid[5][8]; // 5行8列の整数配列

初期化は、複数の方法で行えます。リテラルによる初期化は直感的で効率的です:

int matrix[3][4] = {
    {10, 20, 30, 40},
    {50, 60, 70, 80},
    {90, 100, 110, 120}
};

動的入力では、二重ループを用いてユーザー入力や外部データを格納します:

int data[3][4];
for (int row = 0; row < 3; ++row) {
    for (int col = 0; col < 4; ++col) {
        cin >> data[row][col];
    }
}

要素のアクセスと出力

要素へのアクセスは、行インデックスと列インデックスの組み合わせで行われます。出力も同様に二重ループで実装します:

for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 4; ++j) {
        cout << data[i][j] << " ";
    }
    cout << endl;
}

最大値の検出

配列内の最大値を探索するには、全要素を走査し、現在の最大値と比較します:

int maxValue = data[0][0];
for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 4; ++j) {
        if (data[i][j] > maxValue) {
            maxValue = data[i][j];
        }
    }
}
cout << "最大値: " << maxValue << endl;

各行のソート

二次元配列の各行を独立してソートするには、各インデックスに対してバブルソートを適用します:

void sortRows(int arr[][4], int rows) {
    for (int r = 0; r < rows; ++r) {
        for (int i = 0; i < 4 - 1; ++i) {
            for (int j = 0; j < 4 - i - 1; ++j) {
                if (arr[r][j] > arr[r][j + 1]) {
                    swap(arr[r][j], arr[r][j + 1]);
                }
            }
        }
    }
}

行列の90度回転(原地処理)

正方行列を効率よく回転させるには、転置行の反転の組み合わせを利用します。この手法は追加メモリを必要とせず、空間計算量をO(1)に抑えられます。

void rotateSquareMatrix(vector<vector<int>>& mat) {
    int n = mat.size();
    
    // 転置: (i,j) ↔ (j,i)
    for (int i = 0; i < n; ++i) {
        for (int j = i + 1; j < n; ++j) {
            swap(mat[i][j], mat[j][i]);
        }
    }
    
    // 各行を反転
    for (int i = 0; i < n; ++i) {
        reverse(mat[i].begin(), mat[i].end());
    }
}

このアルゴリズムは、次のような変換を実現します:

初期行列:

1  2  3
4  5  6
7  8  9

回転後:

7  4  1
8  5  2
9  6  3

行の挿入

二次元配列に新しい行を挿入するには、既存の要素を後方にシフトし、空いた位置に新しいデータを配置します。以下は末尾への挿入例です:

void insertRowAtEnd(int arr[][4], int& rows) {
    if (rows < 5) { // 配列の最大行数を制限
        int newRow[] = {13, 14, 15, 16};
        for (int j = 0; j < 4; ++j) {
            arr[rows][j] = newRow[j];
        }
        rows++;
    }
}

中間挿入や先頭挿入も同様に、対象行以降の要素を右シフトして実現できます。

注意点

二次元配列は、メモリ上では連続的に配置されますが、各「行」は独立した一時配列として扱われます。そのため、関数引数として渡す際には列数を明示する必要があります:

void processGrid(int grid[][4], int rows); // OK
void processGrid(int grid[][], int rows); // エラー:列数未指定

また、標準ライブラリのstd::vector<std::vector<int>>を使用すれば、動的サイズや不均一な行長にも対応可能ですが、静的配列と比べてメモリ管理のオーバーヘッドが発生します。

タグ: C++ 二次元配列 配列操作 行列回転 バブルソート

5月15日 05:27 投稿