std::lista w C++ z Przykładem

⚡ Inteligentne podsumowanie

std::lista w C++ jest kontenerem sekwencji zaimplementowanym w postaci listy dwukierunkowo powiązanej, umożliwiającym szybkie wstawianie i usuwanie elementów w dowolnej pozycji, a jednocześnie przechowującym elementy w pamięci nieciągłej i obsługującym dwukierunkowy dostęp sekwencyjny zamiast dostępu losowego.

  • 🔗 Lista dwukierunkowo powiązana: Każdy element zachowuje odnośniki do poprzedniego i następnego węzła, więc dane std::list znajdują się w pamięci nieciągłej.
  • ⚡ Szybkie wstawianie i usuwanie: Dodawanie lub usuwanie elementu w znanej pozycji odbywa się w czasie stałym, w przeciwieństwie do wektora, który przesuwa elementy.
  • ???? Brak dostępu losowego: Do elementów można dotrzeć poprzez sekwencyjne przechodzenie z jednego końca do drugiego, dlatego indeksowanie takie jak list[3] jest niedostępne.
  • 🧩 Konstruktorzy: Konstruktory domyślne, wypełniające, zakresowe, kopiujące, przenoszące i inicjujące-listy tworzą std::list na różne sposoby.
  • 🛠️. Funkcje członkowskie: push_front(), push_back(), insert(), erase(), size(), reverse() i merge() zarządzają zawartością listy.
  • 🤖 Pomoc AI: GitHub Copilot i podobne narzędzia wspomagają deklaracje std::list, iteratory oraz logikę wstawiania i usuwania z krótkiego komentarza.

std::lista w C++

Co to jest std::list?

In C++, std::list odnosi się do kontenera pamięci masowej. Std::list umożliwia wstawianie i usuwanie elementów z dowolnego miejsca. Std::list jest implementowany jako lista dwukierunkowo powiązana. Oznacza to, że dostęp do danych listy jest dwukierunkowy i sekwencyjny.

Lista Standard Template Library nie obsługuje szybkiego dostępu losowego, jednak obsługuje sekwencyjny dostęp ze wszystkich kierunków.

Elementy listy można rozrzucać w różnych fragmentach pamięci. Informacje potrzebne do sekwencyjnego dostępu do danych przechowywane są w kontenerze. Std::list może się rozszerzać i zmniejszać na obu końcach w miarę potrzeb podczas działania. Wewnętrzny alokator automatycznie spełnia wymagania dotyczące przechowywania.

Cechy te rodzą praktyczne pytanie: kiedy właściwie należy sięgnąć po listę?

Po co używać std::list?

Oto powody używania std::list:

  • std::list radzi sobie lepiej w porównaniu do innych kontenerów sekwencji, takich jak tablica i wektor.
  • Mają lepszą wydajność w zakresie wkładania, przesuwania i wyjmowaniatracustawianie elementów z dowolnej pozycji.
  • Lista std::list lepiej sprawdza się także w przypadku algorytmów intensywnie wykonujących tego typu operacje.

Mając już jasne powody, następnym krokiem jest składnia, która je deklaruje.

Składnia listy

Aby zdefiniować std::list, musimy zaimportować plik plik nagłówkowy. Oto składnia definicji std::list:

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

Oto opis powyższych parametrów:

  • T – Definiuje typ zawartego elementu. Możesz zastąpić T dowolnym typem danych, nawet zdefiniowanym przez użytkownika.
  • Alloc – definiuje typ obiektu alokatora. Domyślnie używa szablonu klasy alokatora. Jest zależny od wartości i wykorzystuje prosty model alokacji pamięci.

1 przykład

#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';
	}
}

Wyjście:

Wynik przykładu tworzenia i iteracji std::list

Oto zrzut ekranu kodu:

C++ kod tworzący std::list i drukujący go za pomocą pętli for

Code Wyjaśnienie:

  1. Dołącz plik nagłówkowy algorytmu, aby skorzystać z jego funkcji.
  2. Dołącz plik nagłówkowy iostream, aby móc korzystać z jego funkcji.
  3. Dołącz plik nagłówkowy listy, aby skorzystać z jego funkcji.
  4. Wywołaj funkcję main(). Logikę programu należy dodać w treści tej funkcji.
  5. Utwórz listę o nazwie moja_lista zawierającą zestaw 4 liczb całkowitych.
  6. Użyj dla pętli aby utworzyć zmienną pętli x. Ta zmienna będzie używana do iterowania po elementach listy.
  7. Wydrukuj wartości listy na konsoli.
  8. Koniec treści pętli for.
  9. Koniec treści funkcji main().

C++ Lista funkcji

Oto typowe funkcje std::list:

Funkcjonować OPIS
wstawić() Ta funkcja wstawia nowy element przed pozycją wskazywaną przez iterator.
push_back() Ta funkcja dodaje nowy element na końcu listy.
push_front() Dodaje nowy element na początku listy.
pop_front() Usuwa pierwszy element listy.
rozmiar() Funkcja ta określa liczbę elementów listy.
przód() Aby określić pierwsze elementy listy.
z powrotem() Aby określić ostatni element listy.
odwrócić() Odwraca elementy listy.
łączyć() Łączy dwie posortowane listy.

Konstruktorzy

Oto lista Funkcje dostarczone przez plik nagłówkowy:

  • Domyślny konstruktor std::list::list() - Tworzy pustą listę zawierającą zero elementów.
  • Konstruktor wypełniający std::list::list() — Tworzy listę składającą się z n elementów i przypisuje każdemu elementowi wartość zero (0).
  • Konstruktor zakresu std::list::list() - tworzy listę zawierającą wiele elementów z zakresu od pierwszego do ostatniego.
  • Konstruktor kopiujący std::list::list() - Tworzy listę z kopią każdego elementu zawartego na istniejącej liście.
  • Konstruktor przenoszenia std::list::list() — tworzy listę zawierającą elementy innej listy przy użyciu semantyki przenoszenia.
  • Konstruktor listy inicjującej std::list::list() — tworzy listę z elementami innej listy przy użyciu semantyki przenoszenia.

2 przykład

#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;
}

Wyjście:

Wyjście przykładu konstruktorów std::list

Oto zrzut ekranu kodu:

C++ kod demonstrujący konstruktory std::list domyślne, zakresowe i przenoszące

Code Wyjaśnienie:

  1. Dołącz plik nagłówkowy iostream, aby móc korzystać z jego funkcji.
  2. Dołącz plik nagłówkowy listy, aby skorzystać z jego funkcji.
  3. Dołącz przestrzeń nazw std do kodu, aby używać jej klas bez wywoływania jej.
  4. Wywołaj funkcję main(). Logikę programu należy dodać w treści tej funkcji.
  5. Utwórz pustą listę o nazwie l.
  6. Utwórz listę o nazwie l1 zawierającą zestaw 3 liczb całkowitych.
  7. Utwórz listę o nazwie l2 ze wszystkimi elementami listy o nazwie l1, od początku do końca.
  8. Utwórz listę o nazwie l3, używając semantyki przenoszenia. Lista l3 będzie miała taką samą zawartość jak lista l2.
  9. Wydrukuj rozmiar listy o nazwie l na konsoli wraz z innym tekstem.
  10. Wydrukuj tekst na konsoli.
  11. Utwórz iterator o nazwie iterator i użyj go do iteracji po elementach listy o nazwie l2.
  12. Wydrukuj na konsoli elementy listy o nazwie l2.
  13. Wydrukuj tekst na konsoli.
  14. Utwórz iterator o nazwie iterator i użyj go do iteracji po elementach listy o nazwie l3.
  15. Wydrukuj na konsoli elementy listy o nazwie l3.
  16. Program musi zwrócić wartość po pomyślnym zakończeniu.
  17. Koniec treści funkcji main().

Właściwości kontenera

Oto lista właściwości kontenera:

Właściwość OPIS
Sekwencja Kontenery sekwencji porządkują swoje elementy w ścisłej kolejności liniowej. Dostęp do elementów uzyskuje się poprzez ich pozycję w sekwencji.
Lista podwójnie połączona Każdy element ma informacje o tym, jak zlokalizować poprzednie i następne elementy. Pozwala to na stały czas operacji wstawiania i usuwania.
Obsługuje alokatorów Obiekt alokatora służy do dynamicznego modyfikowania rozmiaru pamięci.

Wstawianie do listy

Istnieją różne funkcje, których możemy użyć do wstawiania wartości do listy. Zaprezentujmy to:

3 przykład

#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';
	}
}

Wyjście:

Dane wyjściowe po wstawieniu elementów do std::list

Oto zrzut ekranu kodu:

C++ kod używający push_front, push_back i insert na std::list

Code Wyjaśnienie:

  1. Dołącz plik nagłówkowy algorytmu, aby skorzystać z jego funkcji.
  2. Dołącz plik nagłówkowy iostream, aby móc korzystać z jego funkcji.
  3. Dołącz plik nagłówkowy listy, aby skorzystać z jego funkcji.
  4. Wywołaj funkcję main(). Logikę programu należy dodać w treści tej funkcji.
  5. Utwórz listę o nazwie moja_lista zawierającą zestaw 4 liczb całkowitych.
  6. Wstaw element 11 na początek listy o nazwie moja_lista.
  7. Wstaw element 18 na koniec listy o nazwie moja_lista.
  8. Utwórz iterator i za jego pomocą znajdź element 10 z listy moja_lista.
  9. Użyj instrukcji if, aby określić, czy powyższy element został znaleziony, czy nie.
  10. Wstaw element 21 przed powyższym elementem, jeśli został znaleziony.
  11. Koniec treści instrukcji if.
  12. Użyj pętli for, aby utworzyć zmienną pętli x. Ta zmienna będzie używana do iteracji po elementach listy.
  13. Wydrukuj wartości listy na konsoli.
  14. Koniec ciała pętli for.
  15. Koniec treści funkcji main().

Elementy, które znajdują się na liście, można równie łatwo z niej usunąć.

Usuwanie z listy

Możliwe jest usuwanie elementów z listy. Funkcja erase() pozwala usunąć element lub zakres elementów z listy.

  • Aby usunąć pojedynczy element, wystarczy przekazać jedną pozycję całkowitą. Element zostanie usunięty.
  • Aby usunąć zakres, przekazujesz iteratory początkowy i końcowy. Pokażemy to.

4 przykład

#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;
}

Wyjście:

Wynik po usunięciu elementu z std::list

Oto zrzut ekranu kodu:

C++ kod wykorzystujący funkcję era na std::list

Code Wyjaśnienie:

  1. Dołącz plik nagłówkowy algorytmu, aby skorzystać z jego funkcji.
  2. Dołącz plik nagłówkowy iostream, aby móc korzystać z jego funkcji.
  3. Dołącz plik nagłówkowy listy, aby skorzystać z jego funkcji.
  4. Dołącz przestrzeń nazw std do naszego programu, aby móc korzystać z jej klas bez wywoływania jej.
  5. Wywołaj funkcję main(). Logikę programu należy dodać w treści tej funkcji.
  6. Utwórz listę o nazwie moja_lista zawierającą zestaw 4 liczb całkowitych.
  7. Wydrukuj tekst na konsoli.
  8. Użyj pętli for, aby utworzyć zmienną pętli x. Ta zmienna będzie używana do iteracji po elementach listy.
  9. Wydrukuj wartości listy na konsoli.
  10. Koniec treści pętli for.
  11. Utwórz iterator i, który wskazuje pierwszy element listy.
  12. Użyj funkcji erase() wskazanej przez iterator i.
  13. Wydrukuj tekst na konsoli.
  14. Użyj pętli for, aby utworzyć zmienną pętli x. Ta zmienna będzie używana do iteracji po elementach listy.
  15. Wydrukuj wartości listy na konsoli. Dzieje się to po usunięciu.
  16. Koniec treści pętli for.
  17. Program musi zwrócić wartość po pomyślnym zakończeniu.
  18. Koniec treści funkcji main().

FAQ

std::vector przechowuje elementy w ciągłej pamięci z dostępem losowym O(1), podczas gdy std::list to lista dwukierunkowa umożliwiająca wstawianie lub usuwanie elementów z dokładnością O(1). Wybierz wektor do indeksowania, a listę do częstych wstawień w środku.

Nie. std::list nie ma operatora dostępu losowego, więc list[2] się nie kompiluje. Do elementu dociera się, iterując od begin() lub end() po jednym węźle na raz, co zajmuje liniowy czas O(n) dla pozycji głębokiej.

std::list jest dwukierunkową listą wiązaną, która porusza się w obu kierunkach i obsługuje metodę push_back. std::forward_list jest jednokierunkową listą wiązaną, która porusza się tylko do przodu, zużywa mniej pamięci na węzeł i nie zapewnia iteratorów size() ani iteratorów odwrotnych.

Wywołaj funkcję członkowską my_list.sort(), która działa w około N log N i utrzymuje stabilność równych elementów. Algorytm std::sort nie zadziała, ponieważ wymaga iteratorów o swobodnym dostępie. Przekaż std::greater do sort(), aby uzyskać kolejność malejącą.

Wstawianie lub usuwanie węzła jest stałe i trwa O(1) po umieszczeniu iteratora na pozycji, ponieważ zmieniają się tylko sąsiednie wskaźniki. Znalezienie tej pozycji poprzez przechodzenie nadal zajmuje O(n) czasu.

Tak. Std::list nie jest zestawem, więc przechowuje powtarzające się wartości swobodnie. Każde push_back, push_front lub insert dodaje nowy węzeł niezależnie od istniejącej zawartości. Użyj std::set, gdy chcesz odrzucić zduplikowane elementy.

Tak. Drugi pilot GitHub Zapisuje deklaracje std::list, pętle iteratorów oraz wywołania insert lub delete z krótkiego komentarza lub nazwy funkcji. Często sugeruje std::vector, gdy ciągłe przechowywanie danych lepiej się sprawdza.

Asystenci kodowania AI automatycznie uzupełniają kod kontenera STL, sygnalizują nieprawidłowe użycie iteratora, konwertują std::list na std::vector i wyjaśniają kompromisy związane ze złożonością. Przyspieszają naukę STL, choć każda sugestia wymaga jeszcze weryfikacji.

Podsumuj ten post następująco: