std::list の C++ 例を挙げて

⚡ スマートサマリー

std::list の C++ これは、二重リンクリストとして実装されたシーケンスコンテナであり、要素を非連続メモリに格納しながら任意の位置への高速な挿入と削除を可能にし、ランダムアクセスではなく双方向のシーケンシャルアクセスをサポートします。

  • 🔗 二重リンクリスト: 各要素は前後のノードへのリンクを保持しているため、std::list のデータは連続していないメモリ領域に格納されます。
  • 高速挿入と削除: 既知の位置に要素を追加または削除する処理は、要素を移動させるベクトルとは異なり、定数時間で実行できます。
  • 🚫 ランダムアクセスなし: 要素には両端から順次走査することで到達できるため、list[3]のようなインデックスは使用できません。
  • 🧩 コンストラクター: デフォルト、フィル、レンジ、コピー、ムーブ、および初期化リストのコンストラクタは、さまざまな方法でstd::listを構築します。
  • 🛠️ メンバーの機能: push_front()、push_back()、insert()、erase()、size()、reverse()、およびmerge()はリストの内容を管理します。
  • 🤖 AI支援: GitHub Copilotや同様のアシスタントは、短いコメントからstd::listの宣言、イテレータ、挿入または削除ロジックを自動生成します。

std::list の C++

std::list とは何ですか?

In C++std::list は、データ格納コンテナを指します。std::list を使用すると、任意の場所から項目を挿入および削除できます。std::list は双方向リンクリストとして実装されています。つまり、リストデータには双方向かつ順次アクセスできます。

標準テンプレートライブラリのリストは高速ランダムアクセスをサポートしていませんが、あらゆる方向からのシーケンシャルアクセスをサポートしています。

リスト要素を異なるメモリ チャンクに分散させることができます。 データへの順次アクセスに必要な情報はコンテナに保存されます。 std::list は、実行時に必要に応じて両端から拡張および縮小できます。 内部アロケータはストレージ要件を自動的に満たします。

これらの特徴は、実践的な疑問を提起する。つまり、実際にリストを使うべきなのはどのような時なのか?

なぜ std::list を使用するのでしょうか?

std::listを使用する理由は以下のとおりです。

  • std::list は、配列やベクトルなどの他のシーケンスコンテナと比較して優れた性能を発揮します。
  • 挿入、移動、排出において優れた性能を発揮しますtrac任意の位置から要素を移動させる。
  • std::list は、このような操作を集中的に実行するアルゴリズムでも優れたパフォーマンスを発揮します。

理由が明確になったので、次のステップはそれを宣言する構文です。

リスト構文

std::list を定義するには、 ヘッダファイル。 std::list 定義構文は次のとおりです。

template < class Type, class Alloc =allocator<T> > class list;

上記のパラメータの説明は次のとおりです。

  • T – 含まれる要素の型を定義します。T には、ユーザー定義型を含む任意のデータ型を指定できます。
  • Alloc – アロケータオブジェクトの型を定義します。デフォルトでは、アロケータクラステンプレートが使用されます。値に依存し、シンプルなメモリ割り当てモデルを使用します。

#include <algorithm>
#include <iostream>
#include <list>
int main() {
	std::list<int> my_list = { 12, 5, 10, 9 };

	for (int x : my_list) {
		std::cout << x << '\n';
	}
}

出力:

std::list の作成と反復の例の出力

コードのスクリーンショットは次のとおりです。

C++ std::listを作成し、forループで出力するコード

Code 説明:

  1. その関数を使用するには、アルゴリズム ヘッダー ファイルをインクルードします。
  2. その機能を使用するには、iostream ヘッダー ファイルをインクルードします。
  3. その機能を使用するには、リスト ヘッダー ファイルをインクルードします。
  4. main() 関数を呼び出します。 プログラム ロジックは、この関数の本体内に追加する必要があります。
  5. 4 つの整数のセットを含む my_list という名前のリストを作成します。
  6. 使用 forループ ループ変数xを作成します。この変数は、リストの要素を反復処理するために使用されます。
  7. リストの値をコンソールに出力します。
  8. for ループの本体の終わり。
  9. main() 関数の本体の終わり。

C++ リスト関数

一般的な std::list 関数は次のとおりです。

演算 詳細説明
インサート() この関数は、イテレータが指す位置の前に新しい項目を挿入します。
プッシュバック() この関数は、リストの最後に新しい項目を追加します。
プッシュ_フロント() リストの先頭に新しい項目を追加します。
ポップフロント() リストの最初の項目を削除します。
サイズ() この関数はリスト要素の数を決定します。
フロント() リストの最初の項目を決定します。
戻る() リストの最後の項目を決定します。
逆行する () リスト項目を反転します。
マージ() XNUMX つのソートされたリストをマージします。

コンストラクター

ここには 機能 によって提供されるヘッダーファイル:

  • デフォルトのコンストラクター std::list::list() - 要素がゼロの空のリストを作成します。
  • Fill コンストラクター std::list::list() - n 個の要素を含むリストを作成し、各要素に値ゼロ (0) を割り当てます。
  • 範囲コンストラクター std::list::list() - 最初から最後までの範囲に多くの要素を含むリストを作成します。
  • コピー コンストラクター std::list::list() - 既存のリストに含まれる各要素のコピーを含むリストを作成します。
  • 移動コンストラクター std::list::list() - 移動セマンティクスを使用して、別のリストの要素を含むリストを作成します。
  • 初期化リスト コンストラクター std::list::list() - 移動セマンティクスを使用して、別のリストの要素を含むリストを作成します。

#include <iostream>
#include <list>
using namespace std;
int main(void) {
	list<int> l;
	list<int> l1 = { 10, 20, 30 };
	list<int> l2(l1.begin(), l1.end());
	list<int> l3(move(l1));  
	cout << "Size of list l: " << l.size() << endl;
	cout << "List l2 contents: " << endl;
	for (auto it = l2.begin(); it != l2.end(); ++it)
	      cout << *it << endl;
	cout << "List l3 contents: " << endl;
	for (auto it = l3.begin(); it != l3.end(); ++it)
		cout << *it << endl;
	return 0;
}

出力:

std::listコンストラクタの例の出力

コードのスクリーンショットは次のとおりです。

C++ std::listのデフォルト、レンジ、ムーブコンストラクタを示すコード

Code 説明:

  1. その機能を使用するには、iostream ヘッダー ファイルをインクルードします。
  2. その機能を使用するには、リスト ヘッダー ファイルをインクルードします。
  3. std 名前空間を呼び出さずにそのクラスを使用するには、コードに std 名前空間を含めます。
  4. main() 関数を呼び出します。 プログラム ロジックは、この関数の本体内に追加する必要があります。
  5. l という名前の空のリストを作成します。
  6. 1 つの整数のセットを含む l3 という名前のリストを作成します。
  7. l2 という名前のリスト内の最初から最後までのすべての要素を含む l1 という名前のリストを作成します。
  8. 移動セマンティクスを使用して l3 という名前のリストを作成します。 リスト l3 はリスト l2 と同じ内容になります。
  9. l という名前のリストのサイズを他のテキストと一緒にコンソールに表示します。
  10. コンソールにテキストを出力します。
  11. it という名前の反復子を作成し、それを使用して l2 という名前のリストの要素を反復処理します。
  12. l2 という名前のリストの要素をコンソールに出力します。
  13. コンソールにテキストを出力します。
  14. it という名前の反復子を作成し、それを使用して l3 という名前のリストの要素を反復処理します。
  15. l3 という名前のリストの要素をコンソールに出力します。
  16. プログラムは正常に完了すると値を返す必要があります。
  17. main() 関数の本体の終わり。

コンテナのプロパティ

コンテナーのプロパティのリストは次のとおりです。

プロパティ 詳細説明
シーケンス シーケンス コンテナーは、要素を厳密な線形シーケンスで順序付けします。 要素はシーケンス内の位置によってアクセスされます。
二重リンクリスト 各要素には、前の要素と次の要素を検索する方法に関する情報があります。これにより、挿入および削除操作に一定の時間がかかります。
アロケータ対応 アロケータ オブジェクトは、ストレージ サイズを動的に変更するために使用されます。

リストへの挿入

リストに値を挿入するために使用できる関数はいくつかあります。それを実例で示しましょう。

#include <algorithm>
#include <iostream>
#include <list>
int main() {
	std::list<int> my_list = { 12, 5, 10, 9 };
	my_list.push_front(11);
	my_list.push_back(18);
	auto it = std::find(my_list.begin(), my_list.end(), 10);
	if (it != my_list.end()) {
		my_list.insert(it, 21);
	}
	for (int x : my_list) {
		std::cout << x << '\n';
	}
}

出力:

std::listに要素を挿入した後の出力

コードのスクリーンショットは次のとおりです。

C++ std::list に対して push_front、push_back、insert を使用するコード

Code 説明:

  1. その関数を使用するには、アルゴリズム ヘッダー ファイルをインクルードします。
  2. その機能を使用するには、iostream ヘッダー ファイルをインクルードします。
  3. その機能を使用するには、リスト ヘッダー ファイルをインクルードします。
  4. main() 関数を呼び出します。 プログラム ロジックは、この関数の本体内に追加する必要があります。
  5. 4 つの整数のセットを含む my_list という名前のリストを作成します。
  6. 要素 11 を my_list という名前のリストの先頭に挿入します。
  7. 要素 18 を my_list という名前のリストの最後に挿入します。
  8. イテレータを作成し、それを使用してリスト my_list から要素 10 を検索します。
  9. if ステートメントを使用して、上記の要素が見つかったかどうかを判断します。
  10. 要素 21 が見つかった場合は、その要素の前に要素 XNUMX を挿入します。
  11. if ステートメントの本文の終わり。
  12. for ループを使用してループ変数 x を作成します。 この変数は、リスト要素を反復処理するために使用されます。
  13. リストの値をコンソールに出力します。
  14. for a ループの本体の終わり。
  15. main() 関数の本体の終わり。

リストに追加した要素は、同じように簡単に削除できる。

リストから削除する

リストから項目を削除することは可能です。erase() 関数を使用すると、リストから項目または項目の範囲を削除できます。

  • 単一の項目を削除するには、整数の位置を XNUMX つ渡すだけです。 項目は削除されます。
  • 範囲を削除するには、開始イテレータと終了イテレータを渡します。これを実例で示しましょう。

#include <algorithm>
#include <iostream>
#include <list>
using namespace std;
int main() {
	std::list<int> my_list = { 12, 5, 10, 9 };
	cout << "List elements before deletion: ";
	for (int x : my_list) {
		std::cout << x << '\n';
	}
	list<int>::iterator i = my_list.begin();
	my_list.erase(i);
	cout << "\nList elements after deletion: ";
	for (int x : my_list) {
		std::cout << x << '\n';
	}
	return 0;
}

出力:

std::listから要素を削除した後の出力

コードのスクリーンショットは次のとおりです。

C++ std::list の erase 関数を使用したコード

Code 説明:

  1. その関数を使用するには、アルゴリズム ヘッダー ファイルをインクルードします。
  2. その機能を使用するには、iostream ヘッダー ファイルをインクルードします。
  3. その機能を使用するには、リスト ヘッダー ファイルをインクルードします。
  4. プログラムに std 名前空間を含めると、そのクラスを呼び出さずに使用できます。
  5. main() 関数を呼び出します。 プログラム ロジックは、この関数の本体内に追加する必要があります。
  6. 4 つの整数のセットを含む my_list という名前のリストを作成します。
  7. コンソールにテキストを出力します。
  8. for ループを使用してループ変数 x を作成します。 この変数は、リスト要素を反復処理するために使用されます。
  9. リストの値をコンソールに出力します。
  10. for ループの本体の終わり。
  11. リストの最初の要素を指す反復子 i を作成します。
  12. イテレータ i が指す Erase() 関数を使用します。
  13. コンソールにテキストを出力します。
  14. for ループを使用してループ変数 x を作成します。 この変数は、リスト要素を反復処理するために使用されます。
  15. リストの値をコンソールに出力します。 これは削除後に表示されます。
  16. for ループの本体の終わり。
  17. プログラムは正常に完了すると値を返す必要があります。
  18. main() 関数の本体の終わり。

よくあるご質問

std::vectorは要素を連続したメモリ領域に格納し、ランダムアクセスはO(1)です。一方、std::listは双方向リンクリストであり、任意の場所への挿入または削除はO(1)です。インデックス付けにはvectorを、頻繁な中間への挿入にはlistを選択してください。

いいえ。std::listにはランダムアクセス演算子がないため、list[2]はコンパイルされません。要素に到達するには、begin()またはend()から一度に1つのノードを反復処理する必要があり、深い位置では線形O(n)の時間がかかります。

std::list は双方向リンクリストで、双方向に走査し、push_back をサポートします。std::forward_list は単方向リンクリストで、前方のみに走査し、ノードあたりのメモリ使用量が少なく、size() や逆方向イテレータは提供しません。

メンバ関数 my_list.sort() を呼び出します。この関数は N log N の時間で実行され、等しい要素は安定して保持されます。std::sort アルゴリズムはランダムアクセス イテレータを必要とするため、この方法では動作しません。降順でソートするには、sort() に std::greater を渡してください。

位置へのイテレータを保持しておけば、ノードの挿入または削除は、隣接するポインタのみが変更されるため、定数時間 O(1) で実行できます。ただし、走査によってその位置を最初に見つけるには、依然として O(n) の時間がかかります。

はい。std::listはセットではないため、重複する値を自由に格納できます。push_back、push_front、insert操作を行うたびに、既存の内容に関係なく新しいノードが追加されます。重複する要素を排除する必要がある場合は、std::setを使用してください。

Yes. GitHubコパイロット 短いコメントまたは関数名から、std::list の宣言、イテレータループ、挿入または削除の呼び出しを生成します。連続した記憶領域の方が適している場合は、std::vector を提案することがよくあります。

AIコーディングアシスタントは、STLコンテナコードの自動補完、イテレータの誤った使用の指摘、std::listをstd::vectorへの変換、複雑性のトレードオフの説明などを行います。これらはSTLの学習を加速させますが、すべての提案は確認が必要です。