C++のSTLのコンテナについてわかりやすく詳しく解説

C++のプログラミングを始めたばかりの方へ、この記事ではC++のSTL(Standard Template Library)について詳しく解説します。

STLは、データを効率的に管理し操作するための便利なツールです。

この記事を読むことで、STLの基本概念や歴史、主要なコンテナの使い方とその利点・欠点について理解できるようになります。

具体的なコード例も交えながら、初心者でもわかりやすく説明していきますので、ぜひ最後までお読みください。

目次から探す

STL(Standard Template Library)とは

STLの概要

STL(Standard Template Library)は、C++の標準ライブラリの一部であり、データ構造とアルゴリズムの集合体です。

STLは、プログラマーが効率的にデータを管理し操作するためのツールを提供します。

これにより、再利用可能なコードを簡単に作成でき、開発の効率が向上します。

STLの歴史と背景

STLは、1990年代初頭にアレクサンドル・ステパノフによって開発されました。

彼の目標は、汎用的で効率的なデータ構造とアルゴリズムを提供することでした。

STLはその後、C++標準ライブラリの一部として採用され、現在ではC++プログラミングにおいて不可欠な要素となっています。

STLの構成要素

STLは主に以下の3つの要素から構成されています:

  • コンテナ:データを格納するためのデータ構造(例:vector、list、mapなど)
  • アルゴリズム:データを操作するための関数(例:sort、find、copyなど)
  • イテレータ:コンテナ内の要素を巡回するためのオブジェクト

コンテナの基本概念

コンテナとは

コンテナは、データを格納し管理するためのデータ構造です。

STLのコンテナは、異なる種類のデータを効率的に格納し、操作するためのインターフェースを提供します。

コンテナの種類

STLのコンテナは大きく3つのカテゴリに分けられます:

  • シーケンスコンテナ:要素が順序通りに格納される(例:vector、deque、list)
  • 連想コンテナ:キーと値のペアで要素が格納される(例:map、set)
  • コンテナアダプタ:他のコンテナを基にした特殊なコンテナ(例:stack、queue)

コンテナの選び方

コンテナを選ぶ際には、以下の点を考慮する必要があります:

  • データの挿入と削除の頻度
  • データの検索の頻度
  • メモリ使用量
  • データの順序性の必要性

シーケンスコンテナ

vector

vectorの基本操作

vectorは動的配列で、サイズが自動的に調整されます。

以下は基本的な操作の例です:

#include <iostream>
#include <vector>
int main() {
    std::vector<int> vec; // 空のvectorを作成
    vec.push_back(1); // 要素を追加
    vec.push_back(2);
    vec.push_back(3);
    for (int i = 0; i < vec.size(); ++i) {
        std::cout << vec[i] << " "; // 要素を出力
    }
    return 0;
}

vectorの利点と欠点

  • 利点:動的にサイズが変更可能、ランダムアクセスが高速
  • 欠点:挿入と削除が遅い(特に中央部)

deque

dequeの基本操作

dequeは両端からの高速な挿入と削除が可能なコンテナです。

以下は基本的な操作の例です:

#include <iostream>
#include <deque>
int main() {
    std::deque<int> deq; // 空のdequeを作成
    deq.push_back(1); // 後ろに要素を追加
    deq.push_front(2); // 前に要素を追加
    for (int i = 0; i < deq.size(); ++i) {
        std::cout << deq[i] << " "; // 要素を出力
    }
    return 0;
}

dequeの利点と欠点

  • 利点:両端からの高速な挿入と削除
  • 欠点:ランダムアクセスがvectorより遅い

list

listの基本操作

listは双方向連結リストで、任意の位置での挿入と削除が高速です。

以下は基本的な操作の例です:

#include <iostream>
#include <list>
int main() {
    std::list<int> lst; // 空のlistを作成
    lst.push_back(1); // 要素を追加
    lst.push_back(2);
    lst.push_back(3);
    for (auto it = lst.begin(); it != lst.end(); ++it) {
        std::cout << *it << " "; // 要素を出力
    }
    return 0;
}

listの利点と欠点

  • 利点:任意の位置での挿入と削除が高速
  • 欠点:ランダムアクセスが遅い

array

arrayの基本操作

arrayは固定サイズの配列で、サイズはコンパイル時に決定されます。

以下は基本的な操作の例です:

#include <iostream>
#include <array>
int main() {
    std::array<int, 3> arr = {1, 2, 3}; // 固定サイズのarrayを作成
    for (int i = 0; i < arr.size(); ++i) {
        std::cout << arr[i] << " "; // 要素を出力
    }
    return 0;
}

arrayの利点と欠点

  • 利点:固定サイズでメモリ効率が良い、ランダムアクセスが高速
  • 欠点:サイズが固定されているため、動的なサイズ変更ができない

forward_list

forward_listの基本操作

forward_listは単方向連結リストで、メモリ効率が良いです。

以下は基本的な操作の例です:

#include <iostream>
#include <forward_list>
int main() {
    std::forward_list<int> flst; // 空のforward_listを作成
    flst.push_front(1); // 要素を追加
    flst.push_front(2);
    flst.push_front(3);
    for (auto it = flst.begin(); it != flst.end(); ++it) {
        std::cout << *it << " "; // 要素を出力
    }
    return 0;
}

forward_listの利点と欠点

  • 利点:メモリ効率が良い、前方からの挿入と削除が高速
  • 欠点:双方向の操作ができない、ランダムアクセスが遅い

連想コンテナ

map

mapの基本操作

mapはキーと値のペアを格納する連想コンテナです。

以下は基本的な操作の例です:

#include <iostream>
#include <map>
int main() {
    std::map<int, std::string> mp; // 空のmapを作成
    mp[1] = "one"; // 要素を追加
    mp[2] = "two";
    mp[3] = "three";
    for (const auto& pair : mp) {
        std::cout << pair.first << ": " << pair.second << "\n"; // 要素を出力
    }
    return 0;
}

mapの利点と欠点

  • 利点:キーによる高速な検索、挿入、削除
  • 欠点:メモリ使用量が多い

multimap

multimapの基本操作

multimapは同じキーを複数持つことができる連想コンテナです。

以下は基本的な操作の例です:

#include <iostream>
#include <map>
int main() {
    std::multimap<int, std::string> mmp; // 空のmultimapを作成
    mmp.insert({1, "one"}); // 要素を追加
    mmp.insert({1, "uno"});
    mmp.insert({2, "two"});
    for (const auto& pair : mmp) {
        std::cout << pair.first << ": " << pair.second << "\n"; // 要素を出力
    }
    return 0;
}

multimapの利点と欠点

  • 利点:同じキーを複数持つことができる
  • 欠点:検索がmapより遅い

set

setの基本操作

setは一意の要素を格納する連想コンテナです。

以下は基本的な操作の例です:

#include <iostream>
#include <set>
int main() {
    std::set<int> st; // 空のsetを作成
    st.insert(1); // 要素を追加
    st.insert(2);
    st.insert(3);
    for (const auto& elem : st) {
        std::cout << elem << " "; // 要素を出力
    }
    return 0;
}

setの利点と欠点

  • 利点:一意の要素を高速に検索、挿入、削除
  • 欠点:メモリ使用量が多い

multiset

multisetの基本操作

multisetは同じ値を複数持つことができる連想コンテナです。

以下は基本的な操作の例です:

#include <iostream>
#include <set>
int main() {
    std::multiset<int> mst; // 空のmultisetを作成
    mst.insert(1); // 要素を追加
    mst.insert(1);
    mst.insert(2);
    for (const auto& elem : mst) {
        std::cout << elem << " "; // 要素を出力
    }
    return 0;
}

multisetの利点と欠点

  • 利点:同じ値を複数持つことができる
  • 欠点:検索がsetより遅い

unordered_map

unordered_mapの基本操作

unordered_mapはハッシュテーブルを使用した連想コンテナです。

以下は基本的な操作の例です:

#include <iostream>
#include <unordered_map>
int main() {
    std::unordered_map<int, std::string> ump; // 空のunordered_mapを作成
    ump[1] = "one"; // 要素を追加
    ump[2] = "two";
    ump[3] = "three";
    for (const auto& pair : ump) {
        std::cout << pair.first << ": " << pair.second << "\n"; // 要素を出力
    }
    return 0;
}

unordered_mapの利点と欠点

  • 利点:平均的に高速な検索、挿入、削除
  • 欠点:順序が保証されない

unordered_multimap

unordered_multimapの基本操作

unordered_multimapは同じキーを複数持つことができるハッシュテーブルです。

以下は基本的な操作の例です:

#include <iostream>
#include <unordered_map>
int main() {
    std::unordered_multimap<int, std::string> ummp; // 空のunordered_multimapを作成
    ummp.insert({1, "one"}); // 要素を追加
    ummp.insert({1, "uno"});
    ummp.insert({2, "two"});
    for (const auto& pair : ummp) {
        std::cout << pair.first << ": " << pair.second << "\n"; // 要素を出力
    }
    return 0;
}

unordered_multimapの利点と欠点

  • 利点:同じキーを複数持つことができる
  • 欠点:順序が保証されない

unordered_set

unordered_setの基本操作

unordered_setはハッシュテーブルを使用した一意の要素を格納するコンテナです。

以下は基本的な操作の例です:

#include <iostream>
#include <unordered_set>
int main() {
    std::unordered_set<int> ust; // 空のunordered_setを作成
    ust.insert(1); // 要素を追加
    ust.insert(2);
    ust.insert(3);
    for (const auto& elem : ust) {
        std::cout << elem << " "; // 要素を出力
    }
    return 0;
}

unordered_setの利点と欠点

  • 利点:平均的に高速な検索、挿入、削除
  • 欠点:順序が保証されない

unordered_multiset

unordered_multisetの基本操作

unordered_multisetは同じ値を複数持つことができるハッシュテーブルです。

以下は基本的な操作の例です:

#include <iostream>
#include <unordered_set>
int main() {
    std::unordered_multiset<int> umst; // 空のunordered_multisetを作成
    umst.insert(1); // 要素を追加
    umst.insert(1);
    umst.insert(2);
    for (const auto& elem : umst) {
        std::cout << elem << " "; // 要素を出力
    }
    return 0;
}

unordered_multisetの利点と欠点

  • 利点:同じ値を複数持つことができる
  • 欠点:順序が保証されない

コンテナアダプタ

stack

stackの基本操作

stackはLIFO(Last In, First Out)構造を持つコンテナアダプタです。

以下は基本的な操作の例です:

#include <iostream>
#include <stack>
int main() {
    std::stack<int> stk; // 空のstackを作成
    stk.push(1); // 要素を追加
    stk.push(2);
    stk.push(3);
    while (!stk.empty()) {
        std::cout << stk.top() << " "; // 要素を出力
        stk.pop(); // 要素を削除
    }
    return 0;
}

stackの利点と欠点

  • 利点:LIFO構造での操作が簡単
  • 欠点:ランダムアクセスができない

queue

queueの基本操作

queueはFIFO(First In, First Out)構造を持つコンテナアダプタです。

以下は基本的な操作の例です:

#include <iostream>
#include <queue>
int main() {
    std::queue<int> que; // 空のqueueを作成
    que.push(1); // 要素を追加
    que.push(2);
    que.push(3);
    while (!que.empty()) {
        std::cout << que.front() << " "; // 要素を出力
        que.pop(); // 要素を削除
    }
    return 0;
}

queueの利点と欠点

  • 利点:FIFO構造での操作が簡単
  • 欠点:ランダムアクセスができない

priority_queue

priority_queueの基本操作

priority_queueは要素が優先度順に格納されるコンテナアダプタです。

以下は基本的な操作の例です:

#include <iostream>
#include <queue>
int main() {
    std::priority_queue<int> pq; // 空のpriority_queueを作成
    pq.push(3); // 要素を追加
    pq.push(1);
    pq.push(2);
    while (!pq.empty()) {
        std::cout << pq.top() << " "; // 要素を出力
        pq.pop(); // 要素を削除
    }
    return 0;
}

priority_queueの利点と欠点

  • 利点:優先度順に要素を取り出せる
  • 欠点:ランダムアクセスができない

コンテナの共通操作

イテレータの使用

イテレータの基本概念

イテレータは、コンテナ内の要素を巡回するためのオブジェクトです。

ポインタのように動作し、コンテナの要素にアクセスするためのインターフェースを提供します。

イテレータの種類

  • 入力イテレータ:読み取り専用
  • 出力イテレータ:書き込み専用
  • 前方イテレータ:前方への読み書き
  • 双方向イテレータ:前後への読み書き
  • ランダムアクセスイテレータ:任意の位置への読み書き

アルゴリズムとの連携

ソート

STLのsort関数を使用してコンテナをソートできます。

以下は例です:

#include <iostream>
#include <vector>
#include <algorithm>
int main() {
    std::vector<int> vec = {3, 1, 2};
    std::sort(vec.begin(), vec.end()); // ソート
    for (const auto& elem : vec) {
        std::cout << elem << " "; // 要素を出力
    }
    return 0;
}

検索

STLのfind関数を使用してコンテナ内の要素を検索できます。

以下は例です:

#include <iostream>
#include <vector>
#include <algorithm

当サイトはリンクフリーです。出典元を明記していただければ、ご自由に引用していただいて構いません。

目次から探す