[C++] 2次元vectorの初期化方法と活用法
C++で2次元vectorを初期化する方法は複数あります。
最も基本的な方法は、コンストラクタを使用してサイズを指定する方法です。
例えば、vector<vector<int>> matrix(rows, vector<int>(cols, initialValue));
とすると、rows
行cols
列の2次元vectorがinitialValue
で初期化されます。
また、リスト初期化を用いてvector<vector<int>> matrix = {{1, 2}, {3, 4}};
のように直接値を指定することも可能です。
2次元vectorは、行列のようなデータ構造を扱う際に便利で、動的にサイズを変更できるため、柔軟なデータ管理が可能です。
例えば、グラフの隣接行列やゲームの盤面の表現に活用されます。
2次元vectorの基礎知識
C++における2次元vectorは、動的にサイズを変更できる便利なデータ構造です。
通常の配列と異なり、vectorはメモリ管理を自動で行い、要素の追加や削除が容易です。
2次元vectorは、vectorの中にvectorを格納することで実現され、行列や表のようなデータを扱う際に非常に役立ちます。
例えば、行列演算やゲームの盤面管理、データテーブルの管理など、さまざまな場面で活用されています。
2次元vectorを効果的に利用するためには、初期化方法や要素のアクセス方法を理解することが重要です。
これにより、効率的なプログラムを作成することが可能になります。
2次元vectorの初期化方法
2次元vectorの初期化方法にはいくつかの方法があります。
それぞれの方法を理解することで、用途に応じた最適な初期化が可能になります。
コンストラクタを用いた初期化
コンストラクタを用いることで、2次元vectorを指定したサイズで初期化することができます。
以下の例では、3行4列の2次元vectorを初期化しています。
#include <iostream>
#include <vector>
int main() {
// 3行4列の2次元vectorを0で初期化
std::vector<std::vector<int>> matrix(3, std::vector<int>(4, 0));
// 初期化された2次元vectorを出力
for (const auto& row : matrix) {
for (int value : row) {
std::cout << value << " ";
}
std::cout << std::endl;
}
return 0;
}
0 0 0 0
0 0 0 0
0 0 0 0
この方法では、すべての要素が指定した初期値で埋められます。
リスト初期化
リスト初期化を用いると、2次元vectorを直接初期化リストで初期化することができます。
以下の例では、異なる値を持つ2次元vectorを初期化しています。
#include <iostream>
#include <vector>
int main() {
// リスト初期化を用いて2次元vectorを初期化
std::vector<std::vector<int>> matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 初期化された2次元vectorを出力
for (const auto& row : matrix) {
for (int value : row) {
std::cout << value << " ";
}
std::cout << std::endl;
}
return 0;
}
1 2 3
4 5 6
7 8 9
リスト初期化は、特定の値で2次元vectorを初期化したい場合に便利です。
ループを用いた動的初期化
ループを用いることで、動的に2次元vectorを初期化することができます。
以下の例では、行と列のインデックスを用いて初期化しています。
#include <iostream>
#include <vector>
int main() {
int rows = 3;
int cols = 4;
std::vector<std::vector<int>> matrix(rows, std::vector<int>(cols));
// ループを用いて動的に初期化
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
matrix[i][j] = i * cols + j;
}
}
// 初期化された2次元vectorを出力
for (const auto& row : matrix) {
for (int value : row) {
std::cout << value << " ";
}
std::cout << std::endl;
}
return 0;
}
0 1 2 3
4 5 6 7
8 9 10 11
この方法は、計算に基づいて要素を初期化したい場合に有用です。
fill関数を用いた初期化
fill関数
を用いることで、2次元vectorのすべての要素を特定の値で埋めることができます。
以下の例では、すべての要素を5で初期化しています。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
int rows = 3;
int cols = 4;
std::vector<std::vector<int>> matrix(rows, std::vector<int>(cols));
// fill関数を用いてすべての要素を5で初期化
for (auto& row : matrix) {
std::fill(row.begin(), row.end(), 5);
}
// 初期化された2次元vectorを出力
for (const auto& row : matrix) {
for (int value : row) {
std::cout << value << " ";
}
std::cout << std::endl;
}
return 0;
}
5 5 5 5
5 5 5 5
5 5 5 5
fill関数
を用いると、特定の値で2次元vectorを効率的に初期化することができます。
2次元vectorの操作
2次元vectorを効果的に利用するためには、要素のアクセスや操作方法を理解することが重要です。
ここでは、基本的な操作方法について説明します。
要素のアクセス方法
2次元vectorの要素にアクセスするには、行と列のインデックスを指定します。
以下の例では、特定の要素にアクセスして値を取得および設定しています。
#include <iostream>
#include <vector>
int main() {
std::vector<std::vector<int>> matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 要素にアクセスして値を取得
int value = matrix[1][2]; // 2行3列目の要素
std::cout << "取得した値: " << value << std::endl;
// 要素にアクセスして値を設定
matrix[0][0] = 10; // 1行1列目の要素を10に設定
// 更新された2次元vectorを出力
for (const auto& row : matrix) {
for (int val : row) {
std::cout << val << " ";
}
std::cout << std::endl;
}
return 0;
}
取得した値: 6
10 2 3
4 5 6
7 8 9
このように、行と列のインデックスを指定することで、特定の要素にアクセスできます。
要素の追加と削除
2次元vectorに要素を追加したり削除したりすることも可能です。
以下の例では、行や列を追加・削除しています。
#include <iostream>
#include <vector>
int main() {
std::vector<std::vector<int>> matrix = {
{1, 2, 3},
{4, 5, 6}
};
// 行を追加
matrix.push_back({7, 8, 9});
// 列を追加
for (auto& row : matrix) {
row.push_back(0); // 各行の末尾に0を追加
}
// 行を削除
matrix.pop_back();
// 列を削除
for (auto& row : matrix) {
row.pop_back(); // 各行の末尾の要素を削除
}
// 更新された2次元vectorを出力
for (const auto& row : matrix) {
for (int val : row) {
std::cout << val << " ";
}
std::cout << std::endl;
}
return 0;
}
1 2 3
4 5 6
この例では、行や列の追加・削除を行うことで、2次元vectorのサイズを動的に変更しています。
サイズの変更
2次元vectorのサイズを変更するには、resizeメソッド
を使用します。
以下の例では、行と列のサイズを変更しています。
#include <iostream>
#include <vector>
int main() {
std::vector<std::vector<int>> matrix(2, std::vector<int>(3, 0));
// 行のサイズを変更
matrix.resize(3);
// 各行の列のサイズを変更
for (auto& row : matrix) {
row.resize(4, 1); // 新しい要素を1で初期化
}
// 更新された2次元vectorを出力
for (const auto& row : matrix) {
for (int val : row) {
std::cout << val << " ";
}
std::cout << std::endl;
}
return 0;
}
0 0 0 1
0 0 0 1
1 1 1 1
resizeメソッド
を使用することで、行や列のサイズを柔軟に変更できます。
イテレーションの方法
2次元vectorの要素をイテレーションするには、ネストされたループを使用します。
以下の例では、すべての要素を出力しています。
#include <iostream>
#include <vector>
int main() {
std::vector<std::vector<int>> matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 2次元vectorの要素をイテレーション
for (const auto& row : matrix) {
for (int val : row) {
std::cout << val << " ";
}
std::cout << std::endl;
}
return 0;
}
1 2 3
4 5 6
7 8 9
このように、ネストされたループを用いることで、2次元vectorのすべての要素にアクセスできます。
2次元vectorの活用法
2次元vectorは、さまざまな場面で活用できる柔軟なデータ構造です。
ここでは、具体的な活用例をいくつか紹介します。
行列の表現
2次元vectorは、行列を表現するのに最適です。
行列演算やデータの格納に利用できます。
以下の例では、2つの行列を加算しています。
#include <iostream>
#include <vector>
int main() {
std::vector<std::vector<int>> matrixA = {
{1, 2, 3},
{4, 5, 6}
};
std::vector<std::vector<int>> matrixB = {
{7, 8, 9},
{10, 11, 12}
};
std::vector<std::vector<int>> result(2, std::vector<int>(3, 0));
// 行列の加算
for (size_t i = 0; i < matrixA.size(); ++i) {
for (size_t j = 0; j < matrixA[i].size(); ++j) {
result[i][j] = matrixA[i][j] + matrixB[i][j];
}
}
// 結果を出力
for (const auto& row : result) {
for (int val : row) {
std::cout << val << " ";
}
std::cout << std::endl;
}
return 0;
}
8 10 12
14 16 18
この例では、2つの行列を要素ごとに加算し、新しい行列を生成しています。
グラフの隣接行列
グラフの隣接行列を表現するのにも2次元vectorは便利です。
以下の例では、無向グラフの隣接行列を作成しています。
#include <iostream>
#include <vector>
int main() {
// 4頂点の無向グラフの隣接行列
std::vector<std::vector<int>> adjacencyMatrix = {
{0, 1, 0, 1},
{1, 0, 1, 0},
{0, 1, 0, 1},
{1, 0, 1, 0}
};
// 隣接行列を出力
for (const auto& row : adjacencyMatrix) {
for (int val : row) {
std::cout << val << " ";
}
std::cout << std::endl;
}
return 0;
}
0 1 0 1
1 0 1 0
0 1 0 1
1 0 1 0
この隣接行列は、頂点間の接続を示しており、グラフの解析に利用できます。
ゲームの盤面管理
ゲームの盤面を管理するのにも2次元vectorは適しています。
以下の例では、簡単なチェス盤を表現しています。
#include <iostream>
#include <vector>
int main() {
// 8x8のチェス盤を表現
std::vector<std::vector<char>> chessBoard(8, std::vector<char>(8, '-'));
// 初期配置
chessBoard[0][0] = 'R'; // ルーク
chessBoard[0][1] = 'N'; // ナイト
chessBoard[0][2] = 'B'; // ビショップ
chessBoard[0][3] = 'Q'; // クイーン
chessBoard[0][4] = 'K'; // キング
chessBoard[0][5] = 'B'; // ビショップ
chessBoard[0][6] = 'N'; // ナイト
chessBoard[0][7] = 'R'; // ルーク
// チェス盤を出力
for (const auto& row : chessBoard) {
for (char piece : row) {
std::cout << piece << " ";
}
std::cout << std::endl;
}
return 0;
}
R N B Q K B N R
- - - - - - - -
- - - - - - - -
- - - - - - - -
- - - - - - - -
- - - - - - - -
- - - - - - - -
- - - - - - - -
この例では、チェスの駒を配置し、盤面を管理しています。
データテーブルの管理
2次元vectorは、データテーブルの管理にも利用できます。
以下の例では、簡単な成績表を作成しています。
#include <iostream>
#include <vector>
#include <string>
int main() {
// 学生の成績表
std::vector<std::vector<std::string>> gradeTable = {
{"名前", "数学", "英語", "科学"},
{"田中", "85", "78", "92"},
{"佐藤", "90", "88", "85"},
{"鈴木", "75", "82", "89"}
};
// 成績表を出力
for (const auto& row : gradeTable) {
for (const std::string& item : row) {
std::cout << item << " ";
}
std::cout << std::endl;
}
return 0;
}
名前 数学 英語 科学
田中 85 78 92
佐藤 90 88 85
鈴木 75 82 89
この例では、学生の名前と成績を2次元vectorで管理し、出力しています。
応用例
2次元vectorは、さまざまな応用分野で活用されています。
ここでは、具体的な応用例をいくつか紹介します。
2次元vectorを用いた画像処理
画像処理では、画像をピクセル単位で操作する必要があります。
2次元vectorを用いることで、画像を効率的に管理できます。
以下の例では、簡単なグレースケール画像を反転しています。
#include <iostream>
#include <vector>
int main() {
// 3x3のグレースケール画像を表現
std::vector<std::vector<int>> image = {
{255, 128, 0},
{64, 192, 32},
{16, 48, 96}
};
// 画像の反転処理
for (auto& row : image) {
for (int& pixel : row) {
pixel = 255 - pixel; // ピクセル値を反転
}
}
// 反転された画像を出力
for (const auto& row : image) {
for (int pixel : row) {
std::cout << pixel << " ";
}
std::cout << std::endl;
}
return 0;
}
0 127 255
191 63 223
239 207 159
この例では、各ピクセルの値を反転することで、画像のネガを生成しています。
2次元vectorを用いたパスファインディング
パスファインディングアルゴリズムでは、2次元vectorを用いてグリッドを表現し、最短経路を探索します。
以下の例では、簡単なグリッド上でのパスファインディングを示しています。
#include <iostream>
#include <vector>
#include <queue>
struct Point {
int x, y;
};
int main() {
// 5x5のグリッドを表現(0は通行可能、1は障害物)
std::vector<std::vector<int>> grid = {
{0, 0, 1, 0, 0},
{0, 1, 0, 1, 0},
{0, 0, 0, 0, 0},
{1, 0, 1, 0, 1},
{0, 0, 0, 0, 0}
};
// スタートとゴールの座標
Point start = {0, 0};
Point goal = {4, 4};
// パスファインディングの実装(幅優先探索)
std::queue<Point> q;
q.push(start);
grid[start.x][start.y] = 2; // 訪問済みを示す
while (!q.empty()) {
Point current = q.front();
q.pop();
if (current.x == goal.x && current.y == goal.y) {
std::cout << "ゴールに到達しました!" << std::endl;
break;
}
// 移動可能な方向(上下左右)
std::vector<Point> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
for (const auto& dir : directions) {
int newX = current.x + dir.x;
int newY = current.y + dir.y;
if (newX >= 0 && newX < grid.size() && newY >= 0 && newY < grid[0].size() && grid[newX][newY] == 0) {
q.push({newX, newY});
grid[newX][newY] = 2; // 訪問済みを示す
}
}
}
return 0;
}
この例では、幅優先探索を用いて、グリッド上のスタートからゴールまでの経路を探索しています。
2次元vectorを用いたデータ解析
データ解析では、2次元vectorを用いてデータセットを管理し、統計的な処理を行います。
以下の例では、データセットの平均値を計算しています。
#include <iostream>
#include <vector>
int main() {
// データセットを表現
std::vector<std::vector<double>> data = {
{1.2, 2.3, 3.4},
{4.5, 5.6, 6.7},
{7.8, 8.9, 9.0}
};
// 各列の平均値を計算
std::vector<double> columnAverages(data[0].size(), 0.0);
for (const auto& row : data) {
for (size_t i = 0; i < row.size(); ++i) {
columnAverages[i] += row[i];
}
}
for (double& avg : columnAverages) {
avg /= data.size();
}
// 平均値を出力
std::cout << "各列の平均値: ";
for (double avg : columnAverages) {
std::cout << avg << " ";
}
std::cout << std::endl;
return 0;
}
各列の平均値: 4.5 5.6 6.36667
この例では、データセットの各列の平均値を計算し、出力しています。
2次元vectorを用いることで、データの管理と解析が容易になります。
まとめ
この記事では、C++における2次元vectorの初期化方法や操作方法、さらには具体的な活用例について詳しく解説しました。
2次元vectorは、行列の表現やグラフの隣接行列、ゲームの盤面管理、データテーブルの管理など、さまざまな場面でその柔軟性と利便性を発揮します。
これらの知識を活かして、実際のプログラミングにおいて2次元vectorを積極的に活用し、より効率的で効果的なコードを書いてみてください。