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の利点と欠点
- 利点:動的にサイズが変更可能、ランダムアクセスが高速
- 欠点:挿入と削除が遅い(特に中央部)
![](https://af-e.net/wp-content/uploads/2024/05/10-300x158.jpg)
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より遅い
![](https://af-e.net/wp-content/uploads/2024/05/2-1-300x158.jpg)
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の利点と欠点
- 利点:任意の位置での挿入と削除が高速
- 欠点:ランダムアクセスが遅い
![](https://af-e.net/wp-content/uploads/2024/05/4-1-300x158.jpg)
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の利点と欠点
- 利点:固定サイズでメモリ効率が良い、ランダムアクセスが高速
- 欠点:サイズが固定されているため、動的なサイズ変更ができない
![](https://af-e.net/wp-content/uploads/2024/05/9-300x158.jpg)
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の利点と欠点
- 利点:メモリ効率が良い、前方からの挿入と削除が高速
- 欠点:双方向の操作ができない、ランダムアクセスが遅い
![](https://af-e.net/wp-content/uploads/2024/05/3-1-300x158.jpg)
連想コンテナ
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の利点と欠点
- 利点:キーによる高速な検索、挿入、削除
- 欠点:メモリ使用量が多い
![](https://af-e.net/wp-content/uploads/2024/05/5-1-300x158.jpg)
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の利点と欠点
- 利点:一意の要素を高速に検索、挿入、削除
- 欠点:メモリ使用量が多い
![](https://af-e.net/wp-content/uploads/2023/06/2-1-300x158.jpg)
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より遅い
![](https://af-e.net/wp-content/uploads/2023/06/10-300x158.jpg)
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構造での操作が簡単
- 欠点:ランダムアクセスができない
![](https://af-e.net/wp-content/uploads/2024/05/7-1-300x158.jpg)
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構造での操作が簡単
- 欠点:ランダムアクセスができない
![](https://af-e.net/wp-content/uploads/2024/05/6-1-300x158.jpg)
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