技術共有

【C初級】リストクラスの予備理解

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1.標準ライブラリリスト親切

リストの最下層は、センチネル ビットを備えた双方向循環リンク リスト構造です。
forward_list の単一リンクリスト構造と比較して、list のイテレータは双方向イテレータです。
Vector などの順次構造のコンテナと比較して、list は任意の位置での挿入と削除の効率が高くなりますが、任意の位置でのランダム アクセスはサポートされていません。
List はテンプレート クラスです。使用する場合は、要素の型を指定する必要があります。

リストクラスを使用する場合、ヘッダーファイルをインクルードする必要があります<list>

2. リストクラスの共通インターフェース

1. 一般的に使用されるコンストラクター

1. デフォルトのコンストラクター。空のリンク リストを構築します。

list();

例えば:

  1. void test()
  2. {
  3. list<int> lt;
  4. }

2. リスト オブジェクトを構築し、n vals で初期化します。

list(size_type n, const value_type& val =  value_type());

例えば:

  1. void test()
  2. {
  3. list<int> lt(3, 1);
  4. for (auto i : lt)
  5. {
  6. cout << i << " ";
  7. }
  8. }

操作結果:

3.リストクラスのコンストラクタをコピー

list(const list& x); 

例えば:

  1. void test()
  2. {
  3. list<int> lt(3, 1);
  4. list<int> lt1(lt);
  5. for (auto i : lt1)
  6. {
  7. cout << i << " ";
  8. }
  9. }

操作結果:

4. イテレータの初期化コンストラクタを使用する

  1. Template<class InputIterator>
  2. list(InputIterator first, InputIterator last);

例えば:

  1. void test()
  2. {
  3. list<int> lt(3, 1);
  4. list<int> lt1(lt.begin(), lt.end());
  5. for (auto i : lt1)
  6. {
  7. cout << i << " ";
  8. }
  9. }

操作結果:

2. 一般的に使用される容量インターフェイス

それは今でも同じです、ここで一緒に話しましょう。

1.サイズ、空、最大サイズ、サイズ変更

サイズ:戻るリンクされたリストコンテナ内の要素の数。

size_type size() const;

空の:戻るリストコンテナが空かどうか(つまり、サイズは0です)。
(注: この関数はコンテナを一切変更しません。クリアするにはリンクされたリストコンテナの内容については、を参照してください。リスト::クリア。)

bool empty() const;

最大サイズ(一般的には使用されません): 戻り値リンクされたリストコンテナーが保持できる要素の最大数。
(既知のシステムまたはライブラリの実装制限により、これはコンテナが達成できる最大の可能性です)サイズただし、コンテナーがそのサイズに達するという保証はありません。そのサイズに達する前には、ストレージを割り当てることができない可能性があります。 )

size_type max_size() const;

サイズ変更:コンテナに含めるサイズを変更する要素。
もし現在のコンテナより小さいサイズ、コンテンツは以前のものに縮小されます要素を削除し、超過する要素を削除します (そしてそれらを破棄します)。
もし現在のコンテナより大きいサイズ、最後に必要な数の要素を挿入することでコンテンツが展開され、目的の結果が得られます。サイズ。指定されている場合ヴァル、その後、新しい要素は次のように初期化されます。ヴァルコピーしない場合は、値が初期化されます。
(この関数は、コンテナーに要素を挿入または削除することによって、コンテナーの実際の内容を変更することに注意してください。)

void resize (size_type n, value_type val = value_type());

例えば:

  1. void test()
  2. {
  3. list<int> lt(3, 1);
  4. /*list<int> lt1(lt);*/
  5. list<int> lt1(lt.begin(), lt.end());
  6. list<int> lt2;
  7. cout << lt1.size() <<endl;
  8. cout << lt1.empty() <<endl;
  9. cout << lt2.empty() <<endl;
  10. lt1.resize(10);
  11. cout << lt1.size() << endl;
  12. for (auto i : lt1)
  13. {
  14. cout << i << " ";
  15. }
  16. }

操作結果:

3. 共通のアクセスとトラバーサル

1.イテレータ

  1. iterator begin();
  2. const_iterator begin() const;
  3. iterator end();
  4. const_iterator end() const;

イテレータ: リンクされたリスト内の最初のノードと最後のノードの位置を取得するために使用されます。次のポジション (つまり、センチネルのポジション)

例えば:

  1. void test()
  2. {
  3. list<int> lt(5, 2);
  4. list<int> ::iterator it = lt.begin();
  5. while (it != lt.end())
  6. {
  7. cout << *it << " ";
  8. ++it;
  9. }
  10. }

操作結果:

2. 逆反復子

逆イテレータrbegin();

const_reverse_iterator rbegin() 定数;

逆イテレータ rend();

const_reverse_iterator rend() 定数;

逆反復子。rbegin はコンテナ内の最後のノードの位置を取得し、rend はコンテナ内のセンチネル ビットの位置を取得します。

  1. void test()
  2. {
  3. list<int> lt = { 1,23,4,4,5,2 };
  4. list<int> ::reverse_iterator rit = lt.rbegin();
  5. while (rit != lt.rend())
  6. {
  7. cout << *rit << " ";
  8. ++rit;
  9. }
  10. }

操作結果:

注: 逆反復子 rit でも -- の代わりに ++ を使用する必要があります。

3.前面と背面

フロント:

front() を参照します。

const_reference front() 定数;

リンクされたリストの最初のノードに格納されているデータへの参照を返します。

戻る:

参照バック();

const_reference を戻す() const;

リンクされたリストの最後のノードに格納されているデータへの参照を返します。

例えば:

  1. void test()
  2. {
  3. list<int> lt = {213123,123,34524,213};
  4. cout << lt.front() << endl;
  5. cout << lt.back() << endl;
  6. }

操作結果:

4.リストの追加、削除、確認、変更

1) プッシュフロントとポップフロント

Push_front は先頭挿入と呼ばれ、リンクされたリストの先頭から要素を挿入します。

void push_front(const value_type& val);

Pop_front は先頭削除と呼ばれ、リンクリストの先頭から要素を削除します。

void pop_front();

void pop_front();

例えば:

  1. void test()
  2. {
  3. list<int> lt = {213123,123,34524,213};
  4. cout << lt.front() << endl;
  5. lt.push_front(21345);
  6. cout << lt.front() << endl;
  7. lt.pop_front();
  8. cout << lt.front() << endl;
  9. }

操作結果:

2) プッシュバックとポップバック

Push_back は末尾挿入と呼ばれ、リンクされたリストの末尾から要素を挿入します。

void プッシュバック(const value_type& val);

Pop_back は末尾削除と呼ばれ、リンクされたリストの末尾から要素を削除します。

void pop_back();

例えば:

  1. void test()
  2. {
  3. list<int> lt = {213123,123,34524,213};
  4. cout << lt.back() << endl;
  5. lt.push_back(21345);
  6. cout << lt.back() << endl;
  7. lt.pop_back();
  8. cout << lt.back() << endl;
  9. }

操作結果:

3) 見つける

  1. template <class InputIterator, class T>
  2. InputIterator find(InputIterator first, InputIterator last, const T& val);

2 つのイテレータの範囲で val を検索し、それが配置されているイテレータを返します。

例えば:

  1. void test()
  2. {
  3. list<int> lt;
  4. for (int i = 0; i < 3; i++)
  5. {
  6. lt.push_back(i);
  7. }
  8. list<int>::iterator pos = find(lt.begin(), lt.end(), 1);
  9. *pos = 114514;
  10. for (auto i : lt)
  11. {
  12. cout << i << " ";
  13. }
  14. }

操作結果:

注: この関数は list のメンバー関数ではなく、標準ライブラリ内の関数です。複数のコンテナーが find 関数を共有します。

ご覧のとおり、リストのイテレータを直接逆参照してその内容を変更できますが、イテレータはノードを指すべきではないでしょうか?逆参照するとデータが変更されるのはなぜですか?

実際、リストのイテレータは、元のエコロジー ポインタを使用してシミュレートおよび実装されず、最後にカプセル化する必要があります。これは、リストのシミュレートされた実装のソース コードに反映されます。

4)挿入

イテレータ挿入(イテレータ位置、const value_type& val);

void insert(イテレータの位置、size_type n、const value_type& val);

————————————————————————————————————————

テンプレート<class InputIterator>

void insert(イテレータの位置、InputIterator の最初、InputIterator の最後);

位置の前に 1 つ以上の要素を挿入します

例えば:

  1. void test()
  2. {
  3. list<int> lt;
  4. for (int i = 0; i < 3; i++)
  5. {
  6. lt.push_back(i);
  7. }
  8. list<int>::iterator pos = find(lt.begin(), lt.end(), 1);
  9. lt.insert(pos, 8848);
  10. for (auto i : lt)
  11. {
  12. cout << i << " ";
  13. }
  14. }

操作結果:

注意深い学生は、リストの挿入操作がイテレータが無効になることはありませんpos が指すノードは変更されず、相対位置も変わらないためです。

ただし、リストの削除操作により反復子は確実に無効になり、削除されたノードを指す反復子のみが無効になり、他の反復子には影響しません。

5) 消去する

  1. iterator erase(iterator position);
  2. iterator erase(iterator first, iterator last);

位置の要素、または範囲 [first, last) 内のすべての要素を削除します。

例えば:

  1. void test()
  2. {
  3. list<int> lt;
  4. for (int i = 0; i < 3; i++)
  5. {
  6. lt.push_back(i);
  7. }
  8. list<int>::iterator pos = find(lt.begin(), lt.end(), 1);
  9. lt.erase(lt.begin());
  10. for (auto i : lt)
  11. {
  12. cout << i << " ";
  13. }
  14. }

操作結果:

  1. void test()
  2. {
  3. list<int> lt;
  4. for (int i = 0; i < 3; i++)
  5. {
  6. lt.push_back(i);
  7. }
  8. list<int>::iterator pos = find(lt.begin(), lt.end(), 2);
  9. lt.erase(lt.begin(),pos);
  10. for (auto i : lt)
  11. {
  12. cout << i << " ";
  13. }
  14. }

操作結果:

6) スワップ

void swap(ベクトル& x);

2 つのリスト オブジェクトを交換する

例えば:

  1. void test()
  2. {
  3. list<int> lt;
  4. list<int> lt2(6, 12);
  5. for (int i = 0; i < 10; i++)
  6. {
  7. lt.push_back(i);
  8. }
  9. lt.swap(lt2);
  10. for (auto i : lt2)
  11. {
  12. cout << i << " ";
  13. }
  14. cout << endl;
  15. }

操作結果:

7)割り当てる

テンプレート<class InputIterator>

void 割り当て(InputIterator 最初、InputIterator 最後);

void を割り当てます(size_type n、const value_type& val);

リストの新しいコンテンツを指定し、現在のコンテンツを置き換えて、ノードの数を変更します。

例えば:

  1. void test()
  2. {
  3. list<int> lt;
  4. for (int i = 0; i < 10; i++)
  5. {
  6. lt.push_back(i);
  7. }
  8. lt.assign(4, 0);
  9. for (auto i : lt)
  10. {
  11. cout << i << " ";
  12. }
  13. }

操作結果:

8)クリア

void をクリアします。

リンクされたリスト内のすべてのノードを削除します

例えば:

  1. void test()
  2. {
  3. list<int> lt;
  4. for (int i = 0; i < 10; i++)
  5. {
  6. lt.push_back(i);
  7. }
  8. lt.clear();
  9. cout << lt.size() << endl;
  10. }

操作結果:

5.リスト順序変更インターフェース

(1)選別

void ソート();

テンプレート<class Compare>

void sort(compを比較します);

リスト構造の特殊性により、反復子は減算演算を実行できないため、標準ライブラリのsort関数は使用できません。

また、C++ ドキュメントでは、標準ライブラリのソートも反復子の種類をランダム アクセス (RandomAccess) に制限していることがわかります。

  1. default (1)
  2. template <class RandomAccessIterator>
  3. void sort (RandomAccessIterator first, RandomAccessIterator last);
  4. custom (2)
  5. template <class RandomAccessIterator, class Compare>
  6. void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

イテレータにはいくつかの機能カテゴリがあります。

  • 一方向反復子、++ のみ実行可能
  • 双方向反復子。++ および -- を指定できます。
  • ランダムな反復子。++、--、+、- を指定できます。

ただし、リストのソート関数は必要ありません。リンクされたリストを直接ソートする効率は、ベクトルにコピーしてソートしてからリンク リストにコピーし戻すよりもはるかに遅いためです。

(2)逆行する

template <class BidirectionalIterator>
  void reverse (BidirectionalIterator first, BidirectionalIterator last);

リンクされたリストを逆にします

例えば:

  1. void test()
  2. {
  3. list<int> lt;
  4. for (int i = 0; i < 10; i++)
  5. {
  6. lt.push_back(i);
  7. }
  8. for (auto i : lt)
  9. {
  10. cout << i << " ";
  11. }
  12. cout << endl;
  13. lt.reverse();
  14. for (auto i : lt)
  15. {
  16. cout << i << " ";
  17. }
  18. cout << endl;
  19. }

操作結果:


間違いがある場合は修正してください。