第9章: 標準テンプレートライブラリ (STL) ①:コンテナ

C++の大きな魅力の一つに、標準テンプレートライブラリ (Standard Template Library, STL) の存在があります。STLは、よく使われるデータ構造やアルゴリズムを、汎用的かつ効率的に実装したライブラリ群です。この章では、STLの心臓部であるコンテナに焦点を当て、データの格納と管理を劇的に楽にする方法を学びます。

STLの全体像: コンテナ、アルゴリズム、イテレータ

STLは、主に3つの要素から構成されています。

  1. コンテナ (Containers): データを格納するためのデータ構造です。vector(可変長配列)やmap(連想配列)など、様々な種類があります。
  2. アルゴリズム (Algorithms): ソート、検索、変換など、コンテナ上のデータに対して操作を行う関数群です。
  3. イテレータ (Iterators): コンテナの要素を指し示し、アルゴリズムがコンテナの種類に依存せずに各要素にアクセスするための統一的なインターフェースを提供します。ポインタを一般化したようなものです。

これら3つが連携することで、C++プログラマは効率的で再利用性の高いコードを素早く書くことができます。この章では「コンテナ」を、次の章では「アルゴリズム」と、それらをつなぐ「イテレータ」の応用を詳しく見ていきます。

std::vector: 最もよく使う可変長配列

std::vectorは、最も基本的で最もよく使われるコンテナです。他の言語でいうところの「リスト」や「動的配列」に相当し、要素を連続したメモリ領域に格納します。

主な特徴:

  • 動的なサイズ: 必要に応じて自動的にサイズが拡張されます。
  • 高速なランダムアクセス: インデックス(添字)を使って [i] の形式で要素に高速にアクセスできます (O(1))。
  • 末尾への高速な追加・削除: push_back()pop_back() を使った末尾への操作は非常に高速です。

std::vectorを使うには、<vector>ヘッダをインクルードする必要があります。

vector_example.cpp

std::vectorは、どのコンテナを使うか迷ったら、まず最初に検討すべきデフォルトの選択肢と言えるほど万能です。

std::map: キーと値のペアを管理する連想配列

std::mapは、キー (key) と値 (value) のペアを管理するためのコンテナです。他の言語の「辞書 (dictionary)」や「ハッシュマップ (hash map)」に似ています。キーを使って値を高速に検索、追加、削除できます。

主な特徴:

  • キーによる高速な検索: キーに基づいて要素が自動的にソートされて格納されるため、検索、挿入、削除が高速です (O(log n))。
  • 一意なキー: std::map内のキーは重複しません。同じキーで値を挿入しようとすると、既存の値が上書きされます。

std::mapを使うには、<map>ヘッダをインクルードする必要があります。

map_example.cpp

std::mapは、キーと値のペアを効率的に管理したい場合に非常に強力なツールです。

その他: 目的に応じたコンテナ

STLには、他にも特定の目的に特化したコンテナが多数用意されています。ここでは代表的なものをいくつか紹介します。

  • std::list: 双方向リスト。要素の途中への挿入・削除が非常に高速 (O(1)) ですが、ランダムアクセスはできません(先頭から順番にたどる必要があります)。<list>ヘッダが必要です。
  • std::set: 重複しない要素の集合を管理します。要素は自動的にソートされます。特定の要素が集合内に存在するかどうかを高速に判定したい場合 (O(log n)) に便利です。<set>ヘッダが必要です。
  • std::unordered_map: std::mapと同様にキーと値のペアを管理しますが、内部的にハッシュテーブルを使うため、平均的な検索・挿入・削除がさらに高速 (O(1)) です。ただし、要素はソートされません。<unordered_map>ヘッダが必要です。
  • std::queue, std::stack: それぞれ先入れ先出し (FIFO)、後入れ先出し (LIFO) のデータ構造を実装するためのコンテナアダプタです。

どのコンテナを選択するかは、プログラムの要件(データのアクセスパターン、挿入・削除の頻度など)によって決まります。まずはstd::vectorを基本とし、必要に応じて他のコンテナを検討するのが良いアプローチです。

この章のまとめ

  • STLは、コンテナアルゴリズムイテレータの3つの主要コンポーネントから構成される、C++の強力な標準ライブラリです。
    • コンテナは、データを格納するためのクラスです。
    • std::vectorは、最も一般的に使われる動的配列で、高速なランダムアクセスと末尾への簡単な要素追加が特徴です。
    • std::mapは、キーと値のペアを管理する連想配列で、キーによる高速な検索が可能です。
    • 他にもstd::list, std::setなど、特定の用途に合わせた様々なコンテナが用意されています。

練習問題1: 数値ベクタの操作

std::vector<int>型の整数のリストに対して、以下の処理を行うプログラムを作成してください。

  1. ベクタに格納されている全ての数値の合計値を計算して表示する。
  2. ベクタの中の最大値を検索して表示する。
  3. ベクタの要素を逆順にして、その内容を表示する。(ヒント:新しいベクタを作っても良いですし、std::swapを使っても構いません)
practice9_1.cpp

練習問題2: 簡単な単語カウンター

英文(スペースで区切られた単語の列)を読み込み、各単語が何回出現したかをカウントするプログラムをstd::map<std::string, int>を使って作成してください。最後に、出現した全単語とその出現回数をアルファベット順に表示してください。

文字列を単語ごとに分割するには、以下のようにstd::istringstreamを使うと便利です。

#include <sstream> std::string text = "this is a sample text"; std::istringstream iss(text); std::string word; while (iss >> word) { // wordには1単語ずつ格納される }
practice9_2.cpp