STLコンテナ

vector, list, map, set など.

vector(動的配列)

最も使用頻度の高いコンテナ。メモリは連続しており、ランダムアクセスが高速です。

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    v.push_back(6);
    v.pop_back();  // 最後の要素を削除
    
    std::cout << "サイズ: " << v.size() << std::endl;
    std::cout << "容量: " << v.capacity() << std::endl;
    
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    return 0;
}

サイズ: 5
容量: 8
1 2 3 4 5

vectorのメモリ管理

reserve() で事前にメモリ確保。shrink_to_fit() で余分な容量を削減します。

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v;
    v.reserve(100);  // 事前に100個分のメモリ確保
    
    // 100個の要素を追加
    for (int i = 0; i < 100; ++i) {
        v.push_back(i);
    }
    
    std::cout << "サイズ: " << v.size() 
              << ", 容量: " << v.capacity() << std::endl;
    
    // 容量を削減
    v.resize(50);  // 要素数を50に
    v.shrink_to_fit();  // 余分な容量を削除
    
    std::cout << "縮小後: サイズ: " << v.size() 
              << ", 容量: " << v.capacity() << std::endl;
    
    return 0;
}

サイズ: 100, 容量: 100
縮小後: サイズ: 50, 容量: 50

deque(両端キュー)

vectorと似ていますが、前後両端への挿入・削除が効率的です。

#include <iostream>
#include <deque>

int main() {
    std::deque<int> dq = {2, 3, 4};
    dq.push_front(1);  // 前に要素追加
    dq.push_back(5);   // 後に要素追加
    dq.pop_front();    // 前から削除
    
    for (int x : dq) std::cout << x << " ";
    std::cout << std::endl;
    
    return 0;
}

2 3 4 5

list(リスト)

双方向リンクリスト。中間への挿入・削除が効率的。ランダムアクセスはできません。

#include <iostream>
#include <list>

int main() {
    std::list<std::string> colors = {"red", "blue"};
    
    auto it = colors.begin();
    ++it;
    colors.insert(it, "green");  // イテレータの位置に挿入
    
    for (const auto& c : colors) {
        std::cout << c << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

red green blue

map(連想配列)

キー-値ペアを保持。キーでソートされています。O(log N)の検索。

#include <iostream>
#include <map>
#include <string>

int main() {
    std::map<std::string, int> ages;
    ages["太郎"] = 25;
    ages["花子"] = 23;
    ages["次郎"] = 28;
    
    // 自動的にキーでソート
    for (const auto& [name, age] : ages) {
        std::cout << name << ": " << age << std::endl;
    }
    
    // 存在確認
    if (ages.count("太郎") > 0) {
        std::cout << "太郎が見つかりました" << std::endl;
    }
    
    return 0;
}

太郎: 25
花子: 23
次郎: 28
太郎が見つかりました

set(セット)

重複なしのソート済み集合。mapと同様にO(log N)。

#include <iostream>
#include <set>
#include <vector>

int main() {
    std::vector<int> data = {5, 2, 8, 2, 1, 8, 3};
    std::set<int> unique(data.begin(), data.end());  // 重複を削除
    
    std::cout << "重複削除後: ";
    for (int x : unique) std::cout << x << " ";
    std::cout << std::endl;
    
    // 挿入と検索
    unique.insert(7);
    if (unique.find(7) != unique.end()) {
        std::cout << "7が見つかりました" << std::endl;
    }
    
    return 0;
}

重複削除後: 1 2 3 5 8
7が見つかりました

unordered_map と unordered_set

ハッシュテーブルベースのコンテナ。ソートされておらず、平均的に O(1) の高速検索。

#include <iostream>
#include <unordered_map>
#include <unordered_set>

int main() {
    // unordered_map: 順序なし、高速検索
    std::unordered_map<std::string, int> scores;
    scores["Alice"] = 85;
    scores["Bob"] = 92;
    scores["Charlie"] = 78;
    
    std::cout << "Alice: " << scores["Alice"] << std::endl;
    
    // unordered_set: 順序なし、ユニーク要素
    std::unordered_set<int> ids = {101, 202, 303, 202};  // 202は1回だけ
    std::cout << "ユニークなID数: " << ids.size() << std::endl;
    
    return 0;
}

Alice: 85
ユニークなID数: 3

よくある誤り

  • 誤り: v[i] で範囲外アクセス → 改善: v.at(i) で例外ポーション
  • 誤り: map["key"] で存在しないキー → 改善: map.find("key") != map.end() で確認
  • 誤り: listに [] でアクセス → 改善: イテレータまたはループで走査
  • 誤り: capacity と size の混同 → vector の容量は size() より大きい場合がある

ポイント

  • vector: 高速ランダムアクセス、背後のメモリは連続
  • deque: 両端への高速插入・削除
  • list: 中間への高速插入・削除、しかしランダムアクセスは遅い
  • map/set: ソート済み、O(log N)検索
  • unordered_map/set: ハッシュベース、平均 O(1) 検索
  • reserve() で事前にメモリ確保して性能向上