Technologieaustausch

[C Elementary] Vorläufiges Verständnis der Listenklasse

2024-07-12

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

1. StandardbibliothekListeArt

Die unterste Ebene der Liste ist eine bidirektionale, zirkulär verknüpfte Listenstruktur mit Sentinel-Bits.
Im Vergleich zur einfach verknüpften Listenstruktur von forward_list ist der Iterator von list ein bidirektionaler Iterator
Im Vergleich zu sequentiell strukturierten Containern wie Vektoren ist die Liste beim Einfügen und Löschen an jeder Position effizienter, unterstützt jedoch keinen wahlfreien Zugriff an jeder Position.
List ist eine Vorlagenklasse. Bei der Verwendung müssen wir den Typ des Elements angeben.

Wenn Sie die Listenklasse verwenden, müssen Sie die Header-Datei einbinden<list>

2. Gemeinsame Schnittstellen der Listenklasse

1. Häufig verwendete Konstruktoren

1. Standardkonstruktor, erstellt eine leere verknüpfte Liste

list();

Zum Beispiel:

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

2. Erstellen Sie ein Listenobjekt und initialisieren Sie es mit n Werten

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

Zum Beispiel:

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

Operationsergebnis:

3.Kopieren Sie den Konstruktor der Listenklasse

list(const list& x); 

Zum Beispiel:

  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. }

Operationsergebnis:

4. Verwenden Sie den Initialisierungskonstruktor des Iterators

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

Zum Beispiel:

  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. }

Operationsergebnis:

2. Häufig verwendete Kapazitätsschnittstellen

Es ist immer noch dasselbe, lasst mich hier gemeinsam darüber reden.

1.Größe,leer,max_size,Größe ändern

Größe:zurückkehrenverlinkte ListeDie Anzahl der Elemente im Container.

size_type size() const;

leer:zurückkehrenListeOb der Behälter leer ist (d. h. seineGrößeist 0).
(Hinweis: Diese Funktion verändert den Container in keiner Weise. Zum Löschenverlinkte ListeDen Inhalt des Behälters finden Sie unterListe::löschen。)

bool empty() const;

maximale Größe(nicht häufig verwendet): Rückkehrverlinkte ListeDie maximale Anzahl von Elementen, die der Container enthalten kann.
(Aufgrund bekannter Einschränkungen bei der System- oder Bibliotheksimplementierung ist dies das maximale Potenzial, das ein Container erreichen kannGröße , es gibt jedoch keine Garantie dafür, dass der Container diese Größe erreicht: Möglicherweise ist er dennoch nicht in der Lage, zu irgendeinem Zeitpunkt vor Erreichen dieser Größe Speicher zuzuweisen. )

size_type max_size() const;

Größe ändern:Ändern Sie die Größe des Containers, den er enthalten sollNElemente.
WennNkleiner als der aktuelle ContainerGröße, wird der Inhalt auf den vorherigen Wert reduziertNElemente entfernen, diejenigen entfernen, die darüber hinausgehen (und sie zerstören).
WennNGrößer als der aktuelle ContainerGrößeAnschließend wird der Inhalt erweitert, indem am Ende die erforderliche Anzahl von Elementen eingefügt wird, um dies zu erreichenN die Größe von.Falls angegebenWert, dann wird das neue Element initialisiertWertKopien, andernfalls werden sie wertinitialisiert.
(Beachten Sie, dass diese Funktion den tatsächlichen Inhalt des Containers ändert, indem sie Elemente in den Container einfügt oder löscht.)

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

Zum Beispiel:

  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. }

Operationsergebnis:

3. Gemeinsamer Zugriff und Durchquerung

1.Iterator

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

Iterator: Wird verwendet, um die Position des ersten Knotens und des letzten Knotens in der verknüpften Liste zu ermittelnNächste Position (d. h. Sentinel-Position)

Zum Beispiel:

  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. }

Operationsergebnis:

2. Umgekehrter Iterator

umgekehrter Iterator rbegin();

rbegin() const;

reverse_iterator rend();

: const_reverse_iterator rend() const;

Umgekehrter Iterator, rbegin ruft die Position des letzten Knotens im Container ab, rend ruft die Position des Sentinel-Bits im Container ab

  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. }

Operationsergebnis:

Hinweis: Das Reverse-Iterator-Rit sollte auch ++ anstelle von -- verwenden.

3.Vorne und Hinten

Vorderseite:

Referenzfront();

const_reference vorne() const;

Gibt einen Verweis auf die Daten zurück, die im ersten Knoten der verknüpften Liste gespeichert sind

zurück:

Referenz zurück();

const_reference zurück() const;

Gibt einen Verweis auf die Daten zurück, die im letzten Knoten der verknüpften Liste gespeichert sind

Zum Beispiel:

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

Operationsergebnis:

4. Liste hinzufügen, löschen, prüfen und ändern

1) push_front und pop_front

push_front wird als Kopfeinfügung bezeichnet und fügt ein Element aus dem Kopf der verknüpften Liste ein

void push_front(const wert_typ& val);

pop_front wird als Kopflöschung bezeichnet und löscht ein Element aus dem Kopf der verknüpften Liste.

ungültige Popup-Front();

void pop_front();

Zum Beispiel:

  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. }

Operationsergebnis:

2) push_back und pop_back

push_back heißt Tail Insertion und fügt ein Element vom Ende der verknüpften Liste ein

void push_back(const wert_typ& val);

pop_back heißt tail deletion und löscht ein Element vom Ende der verknüpften Liste.

ungültiger Popup-Zurück();

Zum Beispiel:

  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. }

Operationsergebnis:

3) finden

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

Finden Sie val im Bereich von zwei Iteratoren und geben Sie den Iterator dort zurück, wo er sich befindet

Zum Beispiel:

  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. }

Operationsergebnis:

Hinweis: Diese Funktion ist keine Mitgliedsfunktion der Liste, sondern eine Funktion in der Standardbibliothek. Mehrere Container teilen sich die Suchfunktion.

Wie Sie sehen, können wir den Iterator der Liste direkt dereferenzieren und seinen Inhalt ändern, aber sollte der Iterator nicht auf den Knoten verweisen? Warum kann die Dereferenzierung die Daten verändern?

Tatsächlich wird der Iterator der Liste nicht mithilfe des ursprünglichen ökologischen Zeigers simuliert und implementiert, sondern muss unten gekapselt werden, was sich im Quellcode der simulierten Implementierung der Liste widerspiegelt.

4) einfügen

Iterator einfügen (Iteratorposition, const value_type & val);

void insert(Iteratorposition, Größentyp n, const Werttyp& Wert);

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

Vorlage<class InputIterator>

void insert(Iteratorposition, InputIterator zuerst, InputIterator zuletzt);

Fügen Sie ein oder mehrere Elemente vor Position ein

Zum Beispiel:

  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. }

Operationsergebnis:

Aufmerksame Schüler haben vielleicht herausgefunden, dass die Einfügeoperation einer Liste funktioniertFührt nicht dazu, dass der Iterator ungültig wird, da der Knoten, auf den pos zeigt, unverändert bleibt und sich die relative Position nicht ändert.

Der Löschvorgang der Liste führt jedoch definitiv dazu, dass der Iterator ungültig wird und nur der Iterator, der auf den gelöschten Knoten zeigt, ungültig wird und andere Iteratoren nicht betroffen sind.

5) löschen

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

Löschen Sie das Element an der Position oder alle Elemente im Bereich [erstes, letztes]

Zum Beispiel:

  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. }

Operationsergebnis:

  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. }

Operationsergebnis:

6) tauschen

void swap(Vektor&x);

Tauschen Sie zwei Listenobjekte aus

Zum Beispiel:

  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. }

Operationsergebnis:

7) zuweisen

Vorlage<class InputIterator>

void zuweisen (InputIterator zuerst, InputIterator zuletzt);

void zuweisen(Größentyp n, const Werttyp& Wert);

Geben Sie neuen Inhalt für die Liste an, ersetzen Sie den aktuellen Inhalt und ändern Sie die Anzahl der Knoten

Zum Beispiel:

  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. }

Operationsergebnis:

8) löschen

ungültig löschen();

Löschen Sie alle Knoten in der verknüpften Liste

Zum Beispiel:

  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. }

Operationsergebnis:

5. Schnittstelle zur Änderung der Listenbestellung

(1)Sortieren

ungültige Sortierung();

Vorlage<class Compare>

void sort(Vergleiche Komp);

Aufgrund der Besonderheit der Listenstruktur kann die Sortierfunktion in der Standardbibliothek nicht verwendet werden, da der Iterator keine Subtraktionsoperationen durchführen kann.

Und in der C++-Dokumentation können wir sehen, dass die Sortierung in der Standardbibliothek auch den Typ des Iterators auf Direktzugriff (RandomAccess) beschränkt.

  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);

Iteratoren haben mehrere Funktionskategorien:

  • Einweg-Iterator, kann nur ++ ausführen
  • Bidirektionaler Iterator, kann ++ und - sein
  • Zufälliger Iterator, kann ++, --, + und - sein

Die Sortierfunktion der Liste ist jedoch nicht erforderlich, da die Effizienz des direkten Sortierens der verknüpften Liste viel langsamer ist als das Kopieren in den Vektor, das Sortieren und das anschließende Zurückkopieren in die verknüpfte Liste.

(2)umkehren

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

Kehren Sie die verknüpfte Liste um

Zum Beispiel:

  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. }

Operationsergebnis:


Wenn es Fehler gibt, korrigieren Sie mich bitte.