C++ コンテナクラス<list>
C++ 標準ライブラリは豊富な機能を提供しており、その中で<list>非常に重要なコンテナクラスであり、要素の集合を格納し、双方向イテレータをサポートしています。
<list>C++ 標準テンプレートライブラリ(STL)内のシーケンスコンテナであり、コンテナ内の任意の位置に要素をすばやく挿入・削除できます。配列やベクター(<vector>)とは異なり、<list>作成時にサイズを指定する必要がなく、メモリを再割り当てすることなく任意の位置に要素を追加または削除できます。
構文
以下は<list>コンテナの基本的な操作です:
- ヘッダファイルをインクルード:
#include <list> - リストの宣言:
std::list<T> mylist;、ここでTはリストに格納される要素の型です。 - 要素の挿入:
mylist.push_back(value); - 要素の削除:
mylist.pop_back();或mylist.erase(iterator); - 要素のアクセス:
mylist.front();とmylist.back(); - リストの走査:イテレータを使用
for (auto it = mylist.begin(); it != mylist.end(); ++it)
特徴
- 双方向イテレーション:
<list>双方向イテレータを提供し、前後に要素を走査できます。 - 動的なサイズ:配列とは異なり、
<list>サイズは動的に変更でき、固定サイズのメモリを事前に割り当てる必要がありません。 - 高速な挿入と削除:リスト内の任意の位置に要素をすばやく挿入または削除でき、ベクターのように多くの要素を移動する必要はありません。
宣言と初期化
<list>宣言と初期化は他のコンテナと同様です:
#include <iostream>
#include <list>
int main() {
std::list<int> lst1; // 空的list
std::list<int> lst2(5); // 包含5个默认初始化元素的list
std::list<int> lst3(5, 10); // 包含5个元素,每个元素为10
std::list<int> lst4 = {1, 2, 3, 4}; // 使用初始化列表
return 0;
}
例
以下は、<list>簡単な例です。リストの作成、要素の追加、リストの走査、結果の出力を含みます。
例
#include <iostream>
#include <list>
int main() {
// 整数型のリストを作成
std::list<int> numbers;
// リストに要素を追加
numbers.push_back(10);
numbers.push_back(20);
numbers.push_back(30);
// リストの最初の要素にアクセスして出力
std::cout << "First element: " << numbers.front() << std::endl;
// リストの最後の要素にアクセスして出力
std::cout << "Last element: " << numbers.back() << std::endl;
// リストを走査してすべての要素を出力
std::cout << "List elements: ";
for (std::list<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// リストの最後の要素を削除
numbers.pop_back();
// 再度リストを走査してすべての要素を出力
std::cout << "List elements after removing the last element: ";
for (std::list<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
#include <list>
int main() {
// 整数型のリストを作成
std::list<int> numbers;
// リストに要素を追加
numbers.push_back(10);
numbers.push_back(20);
numbers.push_back(30);
// リストの最初の要素にアクセスして出力
std::cout << "First element: " << numbers.front() << std::endl;
// リストの最後の要素にアクセスして出力
std::cout << "Last element: " << numbers.back() << std::endl;
// リストを走査してすべての要素を出力
std::cout << "List elements: ";
for (std::list<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// リストの最後の要素を削除
numbers.pop_back();
// 再度リストを走査してすべての要素を出力
std::cout << "List elements after removing the last element: ";
for (std::list<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
出力結果:
First element: 10 Last element: 30 List elements: 10 20 30 List elements after removing the last element: 10 20
よく使われるメンバ関数
以下は<list>よく使われるメンバ関数の一部です:
| 関数 | 説明 |
|---|---|
push_back(const T& val) |
リストの末尾に要素を追加 |
push_front(const T& val) |
リストの先頭に要素を追加 |
pop_back() |
リストの末尾の要素を削除 |
pop_front() |
リストの先頭の要素を削除 |
insert(iterator pos, val) |
指定位置に要素を挿入 |
erase(iterator pos) |
指定位置の要素を削除 |
clear() |
すべての要素をクリア |
size() |
リスト内の要素数を返す |
empty() |
リストが空かどうかを確認 |
front() |
リストの最初の要素を返す |
back() |
リストの最後の要素を返す |
remove(const T& val) |
指定された値に等しいすべての要素を削除 |
sort() |
リスト内の要素をソート |
merge(list& other) |
ソート済みの別のリストをマージ |
reverse() |
リストを反転 |
begin() / end() |
リストの先頭/末尾イテレータを返す |
例
1. 基本操作
例
#include <iostream>
#include <list>
int main() {
std::list<int> lst = {10, 20, 30};
// 要素の挿入と削除
lst.push_front(5); // 先頭に5を挿入
lst.push_back(40); // 末尾に40を挿入
lst.pop_front(); // 先頭の要素を削除
lst.pop_back(); // 末尾の要素を削除
// リストの内容を出力
std::cout << "List elements: ";
for (const auto& elem : lst) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
#include <list>
int main() {
std::list<int> lst = {10, 20, 30};
// 要素の挿入と削除
lst.push_front(5); // 先頭に5を挿入
lst.push_back(40); // 末尾に40を挿入
lst.pop_front(); // 先頭の要素を削除
lst.pop_back(); // 末尾の要素を削除
// リストの内容を出力
std::cout << "List elements: ";
for (const auto& elem : lst) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
2. 指定位置の要素の挿入と削除
例
#include <iostream>
#include <list>
int main() {
std::list<int> lst = {1, 2, 3, 4, 5};
auto it = lst.begin();
std::advance(it, 2); // イテレータを3番目の要素(値3)に移動
lst.insert(it, 10); // 3番目の要素の前に10を挿入
lst.erase(it); // 3番目の要素を削除
// リストの内容を出力
std::cout << "List elements: ";
for (const auto& elem : lst) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
#include <list>
int main() {
std::list<int> lst = {1, 2, 3, 4, 5};
auto it = lst.begin();
std::advance(it, 2); // イテレータを3番目の要素(値3)に移動
lst.insert(it, 10); // 3番目の要素の前に10を挿入
lst.erase(it); // 3番目の要素を削除
// リストの内容を出力
std::cout << "List elements: ";
for (const auto& elem : lst) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
3. ソートと重複除去
例
#include <iostream>
#include <list>
int main() {
std::list<int> lst = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
lst.sort(); // ソート
lst.unique(); // 隣接する重複要素を削除
// リストの内容を出力
std::cout << "Sorted and unique list: ";
for (const auto& elem : lst) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
#include <list>
int main() {
std::list<int> lst = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
lst.sort(); // ソート
lst.unique(); // 隣接する重複要素を削除
// リストの内容を出力
std::cout << "Sorted and unique list: ";
for (const auto& elem : lst) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
4. マージと反転
例
#include <iostream>
#include <list>
int main() {
std::list<int> lst1 = {1, 3, 5, 7};
std::list<int> lst2 = {2, 4, 6, 8};
lst1.merge(lst2); // ソート済みの2つのリストをマージ
lst1.reverse(); // リストを反転
// リストの内容を出力
std::cout << "Merged and reversed list: ";
for (const auto& elem : lst1) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
#include <list>
int main() {
std::list<int> lst1 = {1, 3, 5, 7};
std::list<int> lst2 = {2, 4, 6, 8};
lst1.merge(lst2); // ソート済みの2つのリストをマージ
lst1.reverse(); // リストを反転
// リストの内容を出力
std::cout << "Merged and reversed list: ";
for (const auto& elem : lst1) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
他のコンテナとの比較
| 特性 | std::list | std::vector | std::deque |
|---|---|---|---|
| メモリ構造 | 非連続メモリ、双方向リンクリスト | 連続メモリ | セグメント化された連続メモリ |
| アクセス性能 | シーケンシャルアクセスは速く、ランダムアクセスは遅い | ランダムアクセスは速い | 先頭と末尾のアクセスはどちらも速い |
| 挿入/削除性能 | 任意の位置での挿入・削除が速い | 末尾の挿入は速く、中間は遅い | 先頭と末尾の挿入・削除が速い |
| 適用シーン | 中間で頻繁に挿入/削除する | 効率的なランダムアクセスが必要 | 先頭と末尾で高速な挿入/削除が必要 |
| イテレータの安定性 | 安定しており、要素の挿入や削除によって無効にならない | 挿入・削除によりイテレータが無効になる可能性がある | 挿入・削除によりイテレータが無効になる可能性がある |
注意事項
<list>要素は挿入順に格納され、要素の値でソートされるわけではありません。- というのも
<list>要素は異なるメモリ位置に格納されているため、ランダムアクセスを必要とする場面には適していません。 - ベクターと比較すると、
<list>メモリ使用効率は低くなります。各要素が前後の要素を指すポインタを格納するための追加スペースを必要とするためです。
この簡単な紹介と例を通じて、初心者は C++ の<list>コンテナについて基本的な理解を得て、実際の問題を解決するために使い始めることができるでしょう。