リスト(理解して使用する)
リストとは何ですか
C++ 標準ライブラリでは、std::list
一連の要素を格納するために使用される二重リンク リスト コンテナーです。やなどのコンテナとは異なりstd::vector
、要素はリンク リストのデータ構造を使用して編成されるため、特定の操作において独自の利点とパフォーマンス特性があります。以下は std::list の詳細な紹介です。std::deque
std::list
機能と利点
二重リンク リスト構造:
std::list
二重リンク リストは、要素を格納するために内部的に使用されます。これは、要素の挿入と削除によってメモリの再割り当てや他の要素のコピーが発生しないため、これらの操作の時間計算量は一定であることを意味します。
効率的な挿入および削除操作:リンクされたリスト構造により、要素の挿入および削除の操作効率が非常に高くなります。大量の挿入および削除操作の場合、std::list が他のコンテナーよりも有利になる傾向があります。
イテレータの安定性:ではstd::list
、要素の挿入と削除は、イテレータが指す要素そのものを削除しない限り、イテレータを無効にしません。これにより、トラバース中の挿入および削除操作がより便利かつ安全になります。
占有空間:std::list
各要素は前後の要素へのポインタを格納する必要があるため、配列型コンテナに比べてstd::list
占有空間が大きくなります。
基本操作
push_back()
Andpush_front()
: リンクされたリストの最後と先頭に要素を挿入します。
pop_back()
Andpop_front()
: リンクされたリストの末尾と先頭の要素を削除します。
insert()
: 指定した位置に要素を挿入します。
erase()
: 指定した位置の要素を削除します。
begin()
ANDend()
: リンクされたリストの開始要素と終了要素の後の 1 つの位置を指す反復子を返します。
size()
: リンクされたリスト内の要素の数を返します。
empty()
: リンクされたリストが空かどうかを確認します。
clear()
: リンクされたリスト内のすべての要素をクリアします。
使用例
#include <iostream>
#include <list>
int main() {
std::list<int> myList;
myList.push_back(1);
myList.push_back(2);
myList.push_back(3);
myList.pop_front();
myList.insert(std::next(myList.begin()), 4);
for (const auto& num : myList) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
を使用する場合はstd::list
、メリットとデメリットを比較検討し、実際のシナリオに応じて適切なコンテナを選択する必要があります。要素の頻繁な挿入と削除が必要で、ランダム アクセスが必要ない場合には、std::list
良い選択となる可能性があります。ただし、リンク リストの特性により、std::list
特定の位置にある要素にアクセスするにはリンク リストを横断する必要があるため、要素への高速ランダム アクセスが必要なシナリオには適していないことに注意してください。
std::vector や std::deque などの他のシーケンシャル コンテナと比較した std::list の大きな違いと利点
アドバンテージ:
高い挿入・削除効率:
std::list
二重リンクリストであるため、メモリの再割り当てや要素のコピーを行わず、挿入・削除操作が一定時間で完了します。これにより、std::list
大量の挿入および削除操作を非常に効率的に行うことができます。
イテレータの安定性:std::list
削除操作がイテレータが指す要素そのものでない限り、挿入および削除操作によってイテレータが無効になることはありません。これにより、トラバース中の挿入および削除操作がより便利かつ安全になります。
比較的安定したスペース占有率:std::list
のスペース占有率は比較的安定しており、挿入および削除操作は他の要素のスペース占有率に影響を与えません。
短所:
ランダム アクセスをサポートしません:リンク リストの構造により、
std::list
配列のようなランダム アクセスはサポートされません。特定の位置にある要素にアクセスするには、リンクされたリストの先頭または末尾からトラバースする必要があります。
追加のポインタ オーバーヘッド:std::list
コンテナ内の各要素は、前後の要素へのポインタを格納する必要があるため、スペースの使用量が他のコンテナよりも高くなります。
キャッシュ効率が低い:リンクリストの要素の格納場所がメモリ上で不連続であるため、リンクリストの要素にアクセスする際にキャッシュヒット率が低く、パフォーマンスに影響を与える可能性があります。
イテレータの使用に関する制限:std::list
イテレータは通常のポインタと同様の算術演算 (+ や - など) をサポートしていないため、std::vector
イテレータ演算を のように柔軟に実行できません。
メンバータイプ
リストコンストラクター
std::list
クラスを使用してオブジェクトを作成する場合、さまざまな初期化ニーズを満たすためにさまざまなコンストラクターを使用できます。各コンストラクターとその使用例については、以下で詳しく説明します。
1. デフォルト (1)
このコンストラクターは、空のstd::list
コンテナーを作成するために使用されます。メモリ割り当て戦略を指定するオプションのアロケータ引数を受け入れることができます。
std::list<int> myList; // 创建一个空的 std::list 容器
2.(2)を埋める
std::list
このコンストラクターは、n 個の要素のコンテナーを作成し、それらの要素を に初期化するために使用されますval
。val
異なる値を渡すことで、同じ値を含むコンテナを作成できます。同様に、オプションのアロケーター パラメーターも渡すことができます。
std::list<int> myList(5, 42); // 创建一个包含 5 个元素,每个元素都是 42 的 std::list 容器
3.範囲(3)
このコンストラクターは、反復子の範囲内の要素を使用してコンテナーを[first, last)
作成します。std::list
これにより、イテレータ範囲を使用してコンテナを初期化できるようになります。同様に、オプションのアロケーター引数も受け入れます。
std::vector<int> vec = {
1, 2, 3, 4, 5};
std::list<int> myList(vec.begin(), vec.end()); // 从迭代器范围内的元素创建 std::list 容器
4.コピー(4)
このコンストラクターは、既存のstd::list
Containerx
の同一のコピーを作成するために使用されます。x
新しいコンテナ内のすべての要素がコピーされます。これはコピーコンストラクターです。
std::list<int> originalList = {
1, 2, 3, 4, 5};
std::list<int> copiedList(originalList); // 创建一个原容器的副本
これらのコンストラクターは、特定のニーズに応じて std::list コンテナーを作成するためのさまざまな初期化メソッドを提供します。データ ソースやその他の条件に応じて、適切なコンストラクターを選択してコンテナ オブジェクトを作成します。
リスト反復子 (イテレーター)
1.begin()
iterator begin() noexcept;
このバージョンの は、begin()
コンテナ内の要素を変更するために使用できるイテレータを返します。noexcept
この関数が例外をスローしないことを示します。
std::list<int> myList = {
1, 2, 3, 4, 5};
std::list<int>::iterator it = myList.begin(); // 获取可修改元素的迭代器
*it = 10; // 修改第一个元素的值为 10
const_iterator begin() const noexcept;
このバージョンの は、begin()
コンテナを変更せずに要素にアクセスするための読み取り専用イテレータを返します。const
この関数がコンテナを変更しないことを示します。
const std::list<int> myList = {
1, 2, 3, 4, 5};
std::list<int>::const_iterator cit = myList.begin(); // 获取只读元素的迭代器
int firstElement = *cit; // 读取第一个元素的值
2.end()
iterator end() noexcept;
このバージョンの は、end()
コンテナ内の要素を変更するために使用できるイテレータを返します。noexcept
この関数が例外をスローしないことを示します。このイテレータが指す位置は、実際にはコンテナの終了位置の後の仮想位置であるため、コンテナ内のどの要素も指しません。
std::list<int> myList = {
1, 2, 3, 4, 5};
std::list<int>::iterator it = myList.end(); // 获取可修改元素的迭代器
--it; // 将迭代器前移一个位置,指向最后一个元素
*it = 20; // 修改最后一个元素的值为 20
const_iterator end() const noexcept;
このバージョンの は、end()
コンテナを変更せずに要素にアクセスするための読み取り専用イテレータを返します。const
この関数がコンテナを変更しないことを示します。同様に、このイテレータもコンテナ内の最後の要素の後の仮想位置を指します。
const std::list<int> myList = {
1, 2, 3, 4, 5};
std::list<int>::const_iterator cit = myList.end(); // 获取只读元素的迭代器
--cit; // 将迭代器前移一个位置,指向最后一个元素
int lastElement = *cit; // 读取最后一个元素的值
3.rbegin()
reverse_iterator rbegin() noexcept;
このバージョンの は、rbegin()
コンテナ内の要素を変更するために使用できる逆反復子を返します。noexcept
この関数が例外をスローしないことを示します。この逆反復子はコンテナ内の最後の要素を指し、--
コンテナはデクリメント演算子を通じて前方に移動できます。
std::list<int> myList = {
1, 2, 3, 4, 5};
std::list<int>::reverse_iterator rit = myList.rbegin(); // 获取可修改元素的反向迭代器
*rit = 10; // 修改最后一个元素的值为 10
++rit; // 将反向迭代器往前移动一个位置,指向倒数第二个元素
const_reverse_iterator rbegin() const noexcept;
このバージョンの は、rbegin()
コンテナを変更せずに要素にアクセスするための読み取り専用の逆反復子を返します。const
この関数がコンテナを変更しないことを示します。この逆反復子は最後の要素も指しており、--
コンテナはデクリメント演算子を通じて前方に移動できます。
const std::list<int> myList = {
1, 2, 3, 4, 5};
std::list<int>::const_reverse_iterator crit = myList.rbegin(); // 获取只读元素的反向迭代器
int lastElement = *crit; // 读取最后一个元素的值
++crit; // 将反向迭代器往前移动一个位置,指向倒数第二个元素
4.レンド()
reverse_iterator rend() nothrow;
このバージョンの は、rend()
コンテナ内の要素を変更するために使用できる逆反復子を返します。nothrow
この関数が例外をスローしないことを示します。この逆反復子は、最初の要素の前のコンテナ内の位置を指し、--
デクリメント演算子を通じてコンテナを前方にトラバースできます。
std::list<int> myList = {
1, 2, 3, 4, 5};
std::list<int>::reverse_iterator rit = myList.rend(); // 获取可修改元素的反向迭代器
--rit; // 将反向迭代器往前移动一个位置,指向最后一个元素
*rit = 10; // 修改最后一个元素的值为 10
const_reverse_iterator rend() const nothrow;
このバージョンの は、rend()
コンテナを変更せずに要素にアクセスするための読み取り専用の逆反復子を返します。const
この関数がコンテナを変更しないことを示します。この逆反復子は、最初の要素の前のコンテナの位置も指します。この位置は、デクリメント演算子を介して前方に移動できます。
const std::list<int> myList = {
1, 2, 3, 4, 5};
std::list<int>::const_reverse_iterator crit = myList.rend(); // 获取只读元素的反向迭代器
--crit; // 将反向迭代器往前移动一个位置,指向最后一个元素
int lastElement = *crit; // 读取最后一个元素的值
5. cbegin()、cend()、crbegin()、crend()
const_iterator cbegin() const noexcept;
このメンバー関数は、コンテナーの要素を指す、コンテナーの先頭を指す定数反復子を返します。定数反復子を使用すると、コンテナーの要素を反復処理できますが、要素を変更することはできません。
const_iterator cend() const noexcept;
このメンバー関数は、コンテナーの終わりを指す定数反復子をコンテナーの要素に返します。この反復子はコンテナの終わりを過ぎた位置を表し、通常は反復子ループの終了条件として使用されます。
std::list<int> myList = {
1, 2, 3, 4, 5};
std::list<int>::const_iterator cit = myList.cbegin(); // 获取常量迭代器
for (; cit != myList.cend(); ++cit) {
std::cout << *cit << " "; // 输出容器中的元素,不修改它们
}
const_reverse_iterator crbegin() const noexcept;
このメンバー関数は、コンテナーの要素を指す const reverse イテレータを返し、コンテナーの逆の開始位置を指します。const reverse イテレータを使用すると、コンテナの要素を逆に走査できますが、要素を変更することはできません。
const_reverse_iterator crend() const noexcept;
このメンバー関数は、コンテナーの要素を指す const reverse イテレーターを返し、コンテナーの逆終了位置を指します。この反復子はコンテナーの先頭を超えた位置を表し、通常は逆反復子ループの終了条件として使用されます。
std::list<int> myList = {
1, 2, 3, 4, 5};
std::list<int>::const_reverse_iterator crit = myList.crbegin(); // 获取常量反向迭代器
for (; crit != myList.crend(); ++crit) {
std::cout << *crit << " "; // 反向输出容器中的元素,不修改它们
}
リスト容量関数(Capacity)と要素アクセス関数(Element access)
1. 空()
empty()
はいstd::list
コンテナーのメンバー関数。コンテナーが空かどうかを判断するために使用されます。コンテナーに要素が含まれているかどうかを示すブール値を返します。関数の宣言は次のとおりです。
bool empty() const noexcept;
戻り値: コンテナが空の場合は true、それ以外の場合は false。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList;
if (myList.empty()) {
std::cout << "The list is empty." << std::endl;
} else {
std::cout << "The list is not empty." << std::endl;
}
myList.push_back(42);
if (myList.empty()) {
std::cout << "The list is empty." << std::endl;
} else {
std::cout << "The list is not empty." << std::endl;
}
return 0;
}
上記の例では、まず空のstd::list
コンテナを作成しmyList
、empty()
関数を使用してコンテナが空かどうかを確認し、対応する情報を出力します。次に、push_back
コンテナに要素を追加し、empty()
再度関数を使用してコンテナが空かどうかを確認することで、適切な情報を出力します。
2. サイズ()
size()
std::list
コンテナ内の要素の数を返すコンテナのメンバー関数です。コンテナ内の要素の数を表す符号なし整数型を返します。関数の宣言は次のとおりです。
size_type size() const noexcept;
戻り値: コンテナ内の要素の数、つまりサイズを返します。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList;
myList.push_back(1);
myList.push_back(2);
myList.push_back(3);
std::cout << "Size of the list: " << myList.size() << std::endl;
return 0;
}
上の例では、最初にstd::list
コンテナを作成しmyList
、次にpush_back
関数を使用して 3 つの要素をコンテナに追加します。次に、size()
関数を使用してコンテナーのサイズを取得し、標準出力に出力します。
3. max_size()
max_size()
は、std::list
コンテナが保持できる要素の最大数を返すコンテナのメンバー関数であり、通常はシステム メモリの制約に従います。コンテナの最大サイズを表す符号なし整数型を返します。関数のシグネチャは次のとおりです。
size_type max_size() const noexcept;
戻り値: コンテナーが保持できる要素の最大数を返します。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList;
std::cout << "Max size of the list: " << myList.max_size() << std::endl;
return 0;
}
上記の例では、空のstd::list
コンテナーを作成し、関数をmyList
使用してコンテナーの最大サイズを取得し、それを標準出力に出力しました。max_size()
実際に使用可能な最大サイズは、システム メモリやその他のリソースの制限によって異なることに注意してください。
4.フロント()
front()
std::list
コンテナ内の最初の要素への参照を返すコンテナのメンバー関数です。この関数には 2 つのバージョンがあり、1 つは変更可能なコンテナのオブジェクト用で、もう 1 つは読み取り専用 (const) コンテナのオブジェクト用です。関数のシグネチャは次のとおりです。
reference front();
const_reference front() const;
Reference : コンテナ内の最初の要素への参照を返します。
const_reference :const
コンテナ オブジェクトで呼び出された場合のみ、コンテナ内の最初の要素への定数参照を返します。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {
10, 20, 30};
int& firstElement = myList.front();
const int& constFirstElement = myList.front();
std::cout << "First element: " << firstElement << std::endl;
std::cout << "Const first element: " << constFirstElement << std::endl;
return 0;
}
上の例では、 3 つの整数要素を含むstd::list
コンテナーを作成しましたmyList
。この関数を使用してfront()
コンテナ内の最初の要素への参照を取得し、それをそれぞれ変更可能な参照firstElement
と読み取り専用の定数参照として保存しconstFirstElement
、標準出力に出力します。
5.戻る()
back()
std::list コンテナのメンバー関数であり、コンテナ内の最後の要素への参照を返すために使用されます。この関数には 2 つのバージョンがあり、1 つは変更可能なコンテナのオブジェクト用で、もう 1 つは読み取り専用 (const) コンテナのオブジェクト用です。関数のシグネチャは次のとおりです。
reference back();
const_reference back() const;
Reference : コンテナ内の最後の要素への参照を返します。
const_reference : const コンテナ オブジェクトで呼び出された場合のみ、コンテナ内の最後の要素への定数参照を返します。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {
10, 20, 30};
int& lastElement = myList.back();
const int& constLastElement = myList.back();
std::cout << "Last element: " << lastElement << std::endl;
std::cout << "Const last element: " << constLastElement << std::endl;
return 0;
}
上の例では、 3 つの整数要素を含むstd::list
コンテナーを作成しましたmyList
。この関数を使用してback()
コンテナ内の最後の要素への参照を取得し、それをそれぞれ変更可能な参照lastElement
と読み取り専用の定数参照として保存しconstLastElement
、標準出力に出力します。
リストの追加、削除、確認、変更機能 (Modifiers)
1. 割り当てる
assign
はいstd::list
コンテナのメンバー関数。コンテナの内容を新しい要素に置き換えるために使用されます。この関数には 3 つの異なるバージョンがあります。
イテレータ範囲を使用します。
template <class InputIterator>
void assign (InputIterator first, InputIterator last);
このバージョンでは、範囲を指定するために2 つの反復子の引数first
とを受け入れます。last
コンテナの内容を[first, last)
スコープ内の要素に置き換えます。
繰り返し要素を使用します。
void assign (size_type n, const value_type& val);
このバージョンでは、整数の引数n
と値を受け入れますval
。n
コンテナの内容を値の要素に置き換えますval
。
初期化子リストを使用します。
void assign (initializer_list<value_type> il);
このバージョンでは、初期化子リストを引数として受け入れます。コンテナーの内容を初期化子リストの要素に置き換えます。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList;
myList.assign({
1, 2, 3, 4, 5}); // 使用初始化列表
std::cout << "Size after assigning with initializer list: " << myList.size() << std::endl;
myList.assign(3, 100); // 使用重复元素
std::cout << "Size after assigning with repeated elements: " << myList.size() << std::endl;
std::list<int> anotherList = {
10, 20, 30, 40};
myList.assign(anotherList.begin(), anotherList.end()); // 使用迭代器范围
std::cout << "Size after assigning with iterator range: " << myList.size() << std::endl;
return 0;
}
上の例では、最初に空のstd::list
コンテナーを作成しましたmyList
。次に、関数の異なるバージョンを使用して、assign
コンテナーの内容を個別に置き換えます。最後に、コンテナーのサイズを出力して、操作が成功したことを確認します。
2. emplace_front
template <class... Args>
void emplace_front (Args&&... args);
emplace_front
std::list
コンテナのメンバー関数であり、コンテナの先頭に新しい要素を挿入するために使用されます。指定された位置に要素を直接構築することで、余分なコピーまたは移動操作を回避します。
Args...
この関数は、新しい要素の構築に使用される可変数の引数を受け入れます。emplace_front
一時オブジェクトを作成して挿入することなく、コンテナの先頭に要素を直接挿入する場合に使用します。
使用例:
#include <iostream>
#include <list>
struct Person {
std::string name;
int age;
Person(const std::string& n, int a) : name(n), age(a) {
std::cout << "Constructing " << name << std::endl;
}
};
int main() {
std::list<Person> personList;
personList.emplace_front("zhangsan", 25);
personList.emplace_front("lisi", 30);
personList.emplace_front("wangwu", 28);
std::cout << "Person list contents:" << std::endl;
for (const auto& person : personList) {
std::cout << "Name: " << person.name << ", Age: " << person.age << std::endl;
}
return 0;
}
上の例では、最初に、と というPerson
2 つのメンバー変数を含む名前の構造体を定義しました。次に、空のコンテナを作成し、関数を使用してコンテナの先頭にいくつかの新しいオブジェクトを挿入し、挿入位置に直接構築します。name
age
std::list
personList
emplace_front
Person
emplace_front
のパラメータは、Person
新しいオブジェクトの構築に使用される型のコンストラクターに渡されることに注意してくださいPerson
。そうすることで、追加のコピーまたは移動操作が回避され、効率が向上します。
3.プッシュフロント
push_front
std::list
コンテナのメンバー関数であり、コンテナの先頭に新しい要素を挿入するために使用されます。
この関数には 2 つのバージョンがあります。
void push_front (const value_type& val);
: 定数参照パラメータを受け入れます。これにより、新しい要素が作成され、パラメータの値が新しい要素にコピーされます。
void push_front (value_type&& val);
: 新しい要素を移動して構築するために使用される右辺値参照パラメーターを受け入れます。これにより、追加のコピー操作が回避され、効率が向上します。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList;
int value = 20;
myList.push_front(value); // Copy insert
std::cout << "List contents:" << std::endl;
for (const auto& num : myList) {
std::cout << num << " ";
}
std::cout << std::endl;
myList.push_front(25); // Move insert
std::cout << "List contents after move insert:" << std::endl;
for (const auto& num : myList) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
上記の例では、最初に空のstd::list
コンテナーを作成しmyList
、次にpush_front
関数を使用して定数参照のコピー挿入操作と右辺値参照の移動挿入操作をそれぞれ実行します。ご覧のとおり、右辺値参照バージョンはpush_front
余分なコピー操作を回避できるため、より効率的です。
4.ポップフロント
void pop_front();
std::list の先頭から要素を削除するメンバー関数です。リストの最初の要素が削除され、リストのサイズが 1 単位ずつ縮小されます。
使用例:
std::list<int> myList = {
1, 2, 3, 4, 5};
myList.pop_front(); // 移除第一个元素
上の例では、pop_front()
1 要素が削除され、リストは {2, 3, 4, 5} になります。
5. emplace_back
template <class... Args> void emplace_back (Args&&... args);
std::list
は、 の末尾に新しい要素を挿入する関数です。これにより、要素の構築に必要なパラメータを渡すことにより、追加のコピーまたは移動操作を回避して、リストの最後に要素を直接構築できます。
使用例:
std::list<std::string> myList;
myList.emplace_back("Hello");
myList.emplace_back("World");
上記の例では、emplace_back
関数は 2 つの文字列要素"Hello"
と をリストの最後に直接構築します"World"
。
この関数は、特に大きなオブジェクトをコンテナに格納する場合に、余分な要素の構築やコピー操作を回避するのに役立ち、パフォーマンスを向上させることができます。
6.プッシュバック
void push_back (const value_type& val);
std::list
は、リストの最後に新しい要素を挿入するために使用されるコンテナーのメンバー関数です。定数参照を引数として受け取り、渡された値をリストの最後に挿入します。
使用例:
std::list<int> myList;
myList.push_back(10);
myList.push_back(20);
myList.push_back(30);
上記の例では、関数は整数と をリストの最後にpush_back
それぞれ挿入します。10、20
30
この関数の操作は比較的単純ですが、メモリ割り当てや要素のコピー操作が必要になる場合があります。挿入された要素が比較的大きい場合、追加のパフォーマンス オーバーヘッドが発生する可能性があります。
7. ポップバック
void pop_back();
std::list
コンテナのメンバー関数であり、リストの最後の要素を削除するために使用されます。リストの最後の要素をコンテナから削除し、対応するメモリ リソースを解放します。
使用例:
std::list<int> myList;
myList.push_back(10);
myList.push_back(20);
myList.push_back(30);
myList.pop_back();
上の例では、pop_back
関数は list から要素を削除し30
、 list を作成します[10, 20]
。
pop_back
関数を呼び出す前にリストを空にしてはいけないことに注意してください。空でない場合、未定義の動作が発生します。empty()
この関数を使用して、リストが空かどうかを確認できます。
8. 場所
template <class... Args> iterator emplace (const_iterator position, Args&&... args);
はいstd::list
コンテナーのメンバー関数。指定された位置に新しい要素を挿入し、挿入された要素に要素コンストラクターのパラメーターを渡すために使用されます。
パラメータの説明:
position
: 新しい要素が挿入される位置へのイテレータ。
args
: 新しい要素のコンストラクターに渡されるパラメーター。
この関数は、新しく挿入された要素を指す反復子を返します。
使用例:
std::list<int> myList = {
10, 20, 30};
auto it = myList.begin();
++it; // 移动到第二个元素的位置
myList.emplace(it, 25); // 在第二个元素位置插入值为 25 的元素
上記の例では、emplace
関数は25
2 番目の要素の位置に値を持つ新しい要素を挿入し、リストは になります[10, 25, 20, 30]
。返されたイテレータは、挿入された要素を指します25
。
この関数は、任意の位置に要素を挿入するのに適しており、パラメーターを介して要素のコンストラクターに直接渡すことができます。
9.挿入
iterator insert (iterator position, const value_type& val);
void insert (iterator position, size_type n, const value_type& val);
template <class InputIterator>
void insert (iterator position, InputIterator first, InputIterator last);
iterator insert (iterator position, const value_type& val);
はいstd::list
コンテナーのメンバー関数。指定された位置に新しい要素を挿入するために使用されます。新しい要素の値はval
パラメーターによって決定されます。
パラメータの説明:
position
: 新しい要素が挿入される位置へのイテレータ。
val
: 挿入する要素の値。
この関数は、挿入された要素を指す反復子を返します。
使用例:
std::list<int> myList = {
10, 20, 30};
auto it = myList.begin();
++it; // 移动到第二个元素的位置
myList.insert(it, 25); // 在第二个元素位置插入值为 25 的元素
void insert (iterator position, size_type n, const value_type& val);
これは、同じ値の指定された数の要素を挿入する挿入関数の別のバージョンです。
パラメータの説明:
position
: 新しい要素が挿入される位置へのイテレータ。
n
: 挿入する同一要素の数。
val
: 挿入する要素の値。
template <class InputIterator> void insert (iterator position, InputIterator first, InputIterator last);
これは、指定された反復子の範囲から要素の範囲を挿入する挿入関数の別のバージョンです。
パラメータの説明:
position
: 新しい要素が挿入される位置へのイテレータ。
first
およびlast
: 挿入する要素の範囲へのイテレータ。
これらのinsert
関数はさまざまな挿入方法を提供し、必要に応じて要素をリストに柔軟に追加できます。
10.消去
iterator erase (iterator position);
これは、リストから 1 つ以上の要素を削除するコンテナーのメンバー関数iterator erase (iterator first, iterator last);
です。std::list
iterator erase (iterator position);
指定された位置にある要素を削除し、次の要素を指す反復子を返します。
パラメータの説明:
position
: 削除する要素の位置へのイテレータ。
戻り値: 削除された要素の後の要素を指すイテレータ。
使用例:
std::list<int> myList = {
10, 20, 30, 40};
auto it = myList.begin();
++it; // 移动到第二个元素的位置
myList.erase(it); // 删除第二个元素
iterator erase (iterator first, iterator last);
指定された範囲内の要素を削除し、削除された範囲の後の要素を指す反復子を返します。
パラメータの説明:
first
and last
: 削除する要素の範囲へのイテレータ (最後ではなく最初を含みます)。
戻り値: 削除された範囲の後の要素を指すイテレータ。
使用例:
std::list<int> myList = {
10, 20, 30, 40};
auto it1 = myList.begin();
auto it2 = myList.begin();
std::advance(it2, 2); // 移动到第三个元素的位置
myList.erase(it1, it2); // 删除第一个和第二个元素
これらの関数を使用すると、必要に応じてリストから 1 つ以上の要素を削除し、後続の操作に適切なイテレータを返すことができます。
11. スワップ
void swap(list& x);
std::list
コンテナのメンバー関数であり、現在のリストの内容を別のリストと交換するために使用されますx
。
パラメータの説明:
x
: 現在のリストとコンテンツを交換する別のリスト。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList1 = {
1, 2, 3};
std::list<int> myList2 = {
4, 5, 6};
myList1.swap(myList2); // 交换两个列表的内容
std::cout << "myList1: ";
for (int num : myList1) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << "myList2: ";
for (int num : myList2) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
上の例では、myList1
との内容myList2
が交換され、出力には4 5 6
それぞれ とが表示されます1 2 3
。この関数は、異なるリスト間でコンテンツを交換する場合に非常に便利です。
12. サイズ変更
void resize(size_type n, value_type val = value_type());
はstd::list
コンテナのメンバー関数であり、リストのサイズを調整するために使用されます。
パラメータの説明:
n
:リサイズ後のサイズを指定します。
val
: リストが展開されるときに新しい要素を設定するために使用される値。デフォルト値は、value_type()
型のデフォルト コンストラクターによって作成された値です。
この関数は、リストの末尾に要素を追加または削除することによって、リストのサイズを指定されたサイズに変更しますn
。新しいサイズが現在のサイズより大きい場合、新しい要素は指定された値で埋められます val
。新しいサイズが現在のサイズより小さい場合、冗長な要素は削除されます。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {
1, 2, 3, 4, 5};
myList.resize(3); // 调整列表大小为3
std::cout << "myList after resize to 3: ";
for (int num : myList) {
std::cout << num << " ";
}
std::cout << std::endl;
myList.resize(5, 0); // 调整列表大小为5,并用0填充新元素
std::cout << "myList after resize to 5 with filling 0: ";
for (int num : myList) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
上の例では、resize(3)
最初に を呼び出した後、リスト内の最初の 3 つの要素のみが残り、その後、 を呼び出した後、リストにはresize(5, 0)
合計 1 つの要素があり、そのうち新しく追加された要素が埋められます。5
2
0
13.クリア
void clear();
はいstd::list
コンテナのメンバー関数。リスト内のすべての要素をクリアして、リストを空のリストにするために使用されます。
この関数はリスト内のすべての要素を削除し、リストを空にしますが、リストが占有しているメモリ領域は解放されないため、リストの容量は変わりません。これにより、要素によって占有されているリソースが効果的に再利用されますが、頻繁なメモリ割り当ておよび割り当て解除操作を削減してパフォーマンスを向上させるための容量が確保されます。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {
1, 2, 3, 4, 5};
std::cout << "myList before clear: ";
for (int num : myList) {
std::cout << num << " ";
}
std::cout << std::endl;
myList.clear(); // 清空列表
std::cout << "myList after clear: ";
for (int num : myList) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
上記の例では、最初にクリア前のリスト要素が出力され、その後 を呼び出した後、clear()
リスト内のすべての要素が削除され、クリア後のリスト要素が出力されます。このときリストは空です。
リスト操作関数(Operations)
1. スプライス
void splice (iterator position, list& x);
このメンバー関数は、別のリスト内のすべての要素を現在のリストに移動し、指定された位置の前にx
挿入するために使用されます。リストは移動後は空のリストになります。position
x
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList1 = {
1, 2, 3};
std::list<int> myList2 = {
4, 5, 6};
auto it = myList1.begin();
std::advance(it, 2);
myList1.splice(it, myList2); // 将 myList2 的元素插入到 myList1 中
std::cout << "myList1 after splice: ";
for (int num : myList1) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << "myList2 after splice: ";
for (int num : myList2) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
void splice (iterator position, list& x, iterator i);
x
このメンバー関数は、別のリスト内の要素を現在のリストに移動し、position
指定された位置の前に挿入するために使用されますが、別のリストx
内の反復子i
が指す要素のみを移動します。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList1 = {
1, 2, 3};
std::list<int> myList2 = {
4, 5, 6};
auto it1 = myList1.begin();
std::advance(it1, 1);
auto it2 = myList2.begin();
myList1.splice(it1, myList2, it2); // 将 myList2 中的第一个元素插入到 myList1 中
std::cout << "myList1 after splice: ";
for (int num : myList1) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << "myList2 after splice: ";
for (int num : myList2) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
void splice (iterator position, list& x, iterator first, iterator last);
このメンバー関数は、別のリストx
内の要素の範囲を現在のリストに移動し、指定された位置の前に[first, last)
挿入するために使用されます。position
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList1 = {
1, 2, 3};
std::list<int> myList2 = {
4, 5, 6};
auto it1 = myList1.begin();
std::advance(it1, 1);
auto it2_first = myList2.begin();
auto it2_last = myList2.begin();
std::advance(it2_last, 2);
myList1.splice(it1, myList2, it2_first, it2_last); // 将 myList2 中的前两个元素插入到 myList1 中
std::cout << "myList1 after splice: ";
for (int num : myList1) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << "myList2 after splice: ";
for (int num : myList2) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
これらのsplice
関数を使用すると、要素をコピーしたり削除したりせずに、リスト内の要素を移動したり、あるリストから別のリストに移動したり、同じリスト内の要素の位置を再配置したりすることができます。
2.削除する
void remove (const value_type& val);
val
このメンバー関数は、指定された値に等しいすべての要素をリストから削除するために使用されます。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {
1, 2, 3, 2, 4, 2, 5};
myList.remove(2); // 移除列表中所有值为 2 的元素
std::cout << "myList after remove: ";
for (int num : myList) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
この例では、myList
値が であるリスト内の2
要素が削除され、最終出力は です"1 3 4 5"
。
3.remove_if
template <class Predicate> void remove_if (Predicate pred);
このメンバー関数は、指定された述語関数に従って、pred
特定の条件を満たす要素を削除するために使用されます。
述語関数はpred
1 つのパラメーターを受け取り、要素を削除する必要があるかどうかを判断するために使用されるブール値を返します。述語が を返す場合true
、要素は削除されます。
使用例:
#include <iostream>
#include <list>
bool isEven(int num) {
return num % 2 == 0;
}
int main() {
std::list<int> myList = {
1, 2, 3, 4, 5, 6, 7, 8, 9};
myList.remove_if(isEven); // 移除列表中所有偶数
std::cout << "myList after remove_if: ";
for (int num : myList) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
この例では、myList
リスト内の偶数要素が削除され、最終出力は です"1 3 5 7 9"
。関数isEven
は偶数かどうかを判定する述語関数。
4.ユニークな
void unique();
このメンバー関数は、リスト内の隣接する重複要素を削除するために使用されます。最初に出現した繰り返し要素のみを保持し、後続の繰り返し要素を削除します。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {
1, 2, 2, 3, 4, 4, 4, 5};
myList.unique(); // 移除相邻的重复元素
std::cout << "myList after unique: ";
for (int num : myList) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
この例では、myList
リスト内の隣接する重複要素が削除され、最終出力は です"1 2 3 4 5"
。
template <class BinaryPredicate> void unique (BinaryPredicate binary_pred);
隣接する繰り返し要素を削除する場合、このメンバー関数はカスタム バイナリ述語関数を使用して、binary_pred
それが繰り返し要素であるかどうかを判断します。predicate 関数は 2 つのパラメーターを受け取り、2 つの要素が等しいかどうかを判断するために使用されるブール値を返します。
使用例:
#include <iostream>
#include <list>
bool isEqual(int a, int b) {
return a == b;
}
int main() {
std::list<int> myList = {
1, 2, 2, 3, 4, 4, 4, 5};
myList.unique(isEqual); // 使用 isEqual 判断是否为重复元素
std::cout << "myList after unique with custom predicate: ";
for (int num : myList) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
この例では、ユーザー定義の述語関数を使用して、isEqual
隣接する要素が等しいかどうかを判断し、隣接する重複要素を削除し、最終的な出力は です"1 2 3 4 5"
。
5.マージ
void merge(list& x);
このメンバー関数は、別のリストを現在のリストにマージするために使用されx
、マージされたリストは昇順に並べ替えられます。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList1 = {
1, 3, 5};
std::list<int> myList2 = {
2, 4, 6};
myList1.merge(myList2); // 将 myList2 合并到 myList1 中
std::cout << "myList1 after merge: ";
for (int num : myList1) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
この例では、myList2
リストは にマージされmyList1
、マージされたリストは昇順に並べ替えられ、最終的な出力は です"1 2 3 4 5 6"
。
template <class Compare> void merge(list& x, Compare comp);
このメンバー関数は上記のmerge
関数に似ていますが、マージされた順序を決定するためのカスタム比較関数 comp を提供できます。
使用例:
#include <iostream>
#include <list>
bool descendingOrder(int a, int b) {
return a > b;
}
int main() {
std::list<int> myList1 = {
5, 3, 1};
std::list<int> myList2 = {
6, 4, 2};
myList1.merge(myList2, descendingOrder); // 使用自定义比较函数合并
std::cout << "myList1 after merge with custom comparison: ";
for (int num : myList1) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
descendingOrder
この例では、リストはカスタム比較関数によってmyList2
マージされmyList1
、マージされたリストは降順でソートされ、最終出力は です"6 5 4 3 2 1"
。
6. 並べ替え
void sort();
<
このメンバー関数は、デフォルトで比較に演算子を使用してリストを昇順に並べ替えるのに使用されます。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {
5, 3, 1, 4, 2};
myList.sort(); // 对列表进行升序排序
std::cout << "myList after sorting: ";
for (int num : myList) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
この例では、リスト内の要素が並べ替えられます"1 2 3 4 5"
。
template <class Compare> void sort(Compare comp);
このメンバー関数は上記のメンバー関数と似ていますsort
が、並べ替え順序を決定するためのカスタム比較関数を提供できますcomp
。
使用例:
#include <iostream>
#include <list>
bool descendingOrder(int a, int b) {
return a > b;
}
int main() {
std::list<int> myList = {
5, 3, 1, 4, 2};
myList.sort(descendingOrder); // 使用自定义比较函数进行降序排序
std::cout << "myList after custom sorting: ";
for (int num : myList) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
この例では、カスタム比較関数を通じてdescendingOrder
、リスト内の要素が並べ替えられます"5 4 3 2 1"
。
7. リバース
void reverse();
この関数は、リスト内の要素を逆順に並べ替えるのに使用されます。
使用例:
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {
1, 2, 3, 4, 5};
myList.reverse(); // 将列表中的元素逆序排列
std::cout << "myList after reversing: ";
for (int num : myList) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
この例では、リスト内の要素が逆順にソートされ、 になります"5 4 3 2 1"
。
リストの反復子が無効です
イテレータの無効化とは、イテレータが指すノードが無効であること、つまりノードが削除されることを意味します。リストの基礎となる構造は、先頭ノードを持つ双方向の循環リンク リストであるため、リストの反復子は、リストに挿入されたときに無効化されません。無効になるのは削除されたときだけです。削除されたノードを指す反復は無効化されますが、他の反復子は影響を受けません。
削除に使用するとstd::list
、イテレータが無効になる可能性があります。以下に例を示します。
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {
1, 2, 3, 4, 5};
auto it = myList.begin();
++it; // Move the iterator to the second element
myList.erase(it); // Erase the second element
for (auto num : myList) {
std::cout << num << " ";
}
return 0;
}
上記の例では、erase
関数を使用して 2 番目の要素位置にある要素を削除すると、イテレータit
が指す要素が削除されているため、イテレータは無効になります。無効なイテレータを使用しようとすると、未定義の動作が発生する可能性があります。
これを修正するには、erase
次の有効な要素を指す反復子を返す関数の戻り値を使用します。
#include <iostream>
#include <list>
int main() {
std::list<int> myList = {
1, 2, 3, 4, 5};
auto it = myList.begin();
++it; // Move the iterator to the second element
it = myList.erase(it); // Erase the second element and update the iterator
for (auto num : myList) {
std::cout << num << " ";
}
return 0;
}
この改訂された例では、erase
関数の戻り値でイテレータを更新し、it
イテレータが有効な要素を指していることを確認します。これにより、無効なイテレータの使用によって発生する問題が回避されます。
エピローグ
興味のある友達は作者に注目してください、内容が良いと思うなら、ワンクリックトリプルリンクをお願いします、カニカニ!!!
作るのは簡単ではありません、不正確な点があればご指摘ください
ご訪問ありがとうございます、UUの視聴が私が頑張れるモチベーションになっています
時間をきっかけに、お互いより良い人間になりましょう!!!