ベクトル(動的配列)

サイズが可変の配列。標準ライブラリの vector を学ぶ

概要

通常の配列は、サイズが固定です。 しかし実際のアプリケーションでは、 データが増えたり減ったりするため、 動的にサイズを変更できる配列が必要です。

その役割を果たすのがstd::vectorです。 これは「動的配列」とも呼ばれます。

ベクトルの基本

宣言と初期化

#include <iostream>
#include <vector>

int main() {
    std::vector<int> empty;           // 空のベクトル
    
    std::vector<int> with_size(5);    // 5つの要素(全て0)
    
    std::vector<int> initialized = {1, 2, 3, 4, 5};  // 初期化
    
    for (int x : initialized) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

1 2 3 4 5

要素の追加(push_back)

#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers;
    
    numbers.push_back(10);
    numbers.push_back(20);
    numbers.push_back(30);
    
    std::cout << "サイズ: " << numbers.size() << std::endl;
    
    for (int x : numbers) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

サイズ: 3
10 20 30

要素へのアクセス

std::vector<int> v = {10, 20, 30};

std::cout << v[0] << std::endl;     // 10
std::cout << v.at(1) << std::endl;  // 20(at()は範囲チェック付き)
std::cout << v.front() << std::endl; // 10(最初の要素)
std::cout << v.back() << std::endl;  // 30(最後の要素)

ベクトルと配列の比較

特性 配列 std::vector
サイズ 固定 可変
宣言時 int arr[10] std::vector<int> v
要素追加 不可 push_back()
要素削除 不可 pop_back()
メモリ管理 スタック ヒープ(自動管理)
パフォーマンス 若干高速 若干低速(メリット大)

ベクトルの操作

サイズとキャパシティ

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v;
    
    std::cout << "初期 - Size: " << v.size() << ", Capacity: " << v.capacity() << std::endl;
    
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    
    std::cout << "追加後 - Size: " << v.size() << ", Capacity: " << v.capacity() << std::endl;
    
    return 0;
}

初期 - Size: 0, Capacity: 0
追加後 - Size: 3, Capacity: 4

size() は実際の要素数、 capacity()は確保されたメモリ量です。

要素の削除と挿入

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {10, 20, 30, 40};
    
    v.pop_back();  // 最後の要素を削除
    
    v.insert(v.begin() + 1, 15);  // インデックス1に15を挿入
    
    v.erase(v.begin() + 2);  // インデックス2を削除
    
    for (int x : v) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

10 15 20

実践例

例1: スコア管理アプリ

#include <iostream>
#include <vector>

int main() {
    std::vector<int> scores;
    
    // スコアを入力
    int score;
    while (true) {
        std::cout << "スコア(終了:-1): ";
        std::cin >> score;
        if (score == -1) break;
        scores.push_back(score);
    }
    
    // 統計情報を表示
    int total = 0;
    for (int s : scores) {
        total += s;
    }
    
    std::cout << "個数: " << scores.size() << std::endl;
    std::cout << "合計: " << total << std::endl;
    std::cout << "平均: " << (total / (double)scores.size()) << std::endl;
    
    return 0;
}

例2: 素数フィルター

#include <iostream>
#include <vector>

bool isPrime(int n) {
    if (n < 2) return false;
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) return false;
    }
    return true;
}

int main() {
    std::vector<int> numbers = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
    std::vector<int> primes;
    
    for (int n : numbers) {
        if (isPrime(n)) {
            primes.push_back(n);
        }
    }
    
    std::cout << "素数: ";
    for (int p : primes) {
        std::cout << p << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

素数: 2 3 5 7 11

2次元ベクトル

2次元配列のようにベクトルのベクトルを使えます。

#include <iostream>
#include <vector>

int main() {
    std::vector<std::vector<int>> matrix;
    
    // 3行のベクトルを作成
    for (int i = 0; i < 3; i++) {
        std::vector<int> row;
        for (int j = 0; j < 3; j++) {
            row.push_back(i * 3 + j + 1);
        }
        matrix.push_back(row);
    }
    
    // 表示
    for (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

ポイント

  • std::vectorは動的配列の標準
  • push_back()で要素を追加、pop_back()で削除
  • size()capacity()の違いを理解
  • 配列より使いやすく、メモリも自動管理
  • 2次元ベクトルも簡単に作成可能

よくある誤り

誤り1: 空のベクトルにアクセス

std::vector<int> v;
std::cout << v[0] << std::endl;  // 危険!: アクセス違反

誤り2: at()と[]の混同

std::vector<int> v = {1, 2, 3};
std::cout << v[10] << std::endl;   // 未定義の動作
std::cout << v.at(10) << std::endl; // 例外発生(より安全)

誤り3: イテレータの無効化

std::vector<int> v = {1, 2, 3};
auto it = v.begin();
v.push_back(4);  // メモリ再配置の可能性、イテレータが無効に
// *it はもう使えない

やってみよう

練習1: ユーザーから複数の整数を入力し、合計を計算。

練習2: ベクトルを反転するプログラム。

練習3: 2つのベクトルをマージするプログラム。

チャレンジ: ベクトルを昇順にソートするプログラム(std::sort を使用)。

まとめ

  • std::vectorは modern C++での標準コンテナ
  • 配列の制限を克服し、動的にサイズを変更可能
  • メモリ管理が自動で行われるため、安全
  • 大規模データのアプリケーションで必須