std::seznam v C++ s příkladem

⚡ Chytré shrnutí

std::seznam v C++ je kontejner sekvencí implementovaný jako dvojitě propojený seznam, který umožňuje rychlé vkládání a mazání na libovolné pozici, přičemž prvky jsou ukládány do nesouvislé paměti a podporuje obousměrný sekvenční přístup namísto náhodného přístupu.

  • 🔗 Dvojitě propojený seznam: Každý prvek si uchovává odkazy na svůj předchozí a následující uzel, takže data std::list se nacházejí v nesouvislé paměti.
  • ⚡ Rychlé vkládání a mazání: Přidání nebo odebrání prvku na známé pozici probíhá v konstantním čase, na rozdíl od vektoru, který prvky posouvá.
  • 🚫 Žádný náhodný přístup: Prvky jsou dosaženy sekvenčním procházením z obou konců, takže indexování, jako například list[3], není k dispozici.
  • 🧩 Konstruktéři: Konstruktory Default, Fill, Range, Copy, Move a Initialization-List sestavují std::list různými způsoby.
  • 🛠️ Členské funkce: Funkce push_front(), push_back(), insert(), erase(), size(), reverse() a merge() spravují obsah seznamu.
  • 🤖 Asistence AI: GitHub Copilot a podobní asistenti vytvářejí deklarace std::list, iterátory a vkládají nebo mazají logiku z krátkého komentáře.

std::seznam v C++

Co je to std::list?

In C++, std::list odkazuje na úložný kontejner. std::list umožňuje vkládat a odebírat položky odkudkoli. std::list je implementován jako dvojitě propojený seznam. To znamená, že k datům seznamu lze přistupovat obousměrně a sekvenčně.

Seznam standardních knihoven šablon nepodporuje rychlý náhodný přístup, ale podporuje sekvenční přístup ze všech směrů.

Prvky seznamu můžete rozptýlit do různých částí paměti. Informace potřebné pro sekvenční přístup k datům jsou uloženy v kontejneru. Seznam std::list se může během běhu podle potřeby rozšiřovat a zmenšovat z obou konců. Interní alokátor automaticky splňuje požadavky na úložiště.

Tyto vlastnosti vyvolávají praktickou otázku: kdy byste měli po seznamu skutečně sáhnout?

Proč používat std::list?

Zde jsou důvody pro použití std::list:

  • std::list si vede lépe než jiné kontejnery sekvencí, jako jsou pole a vektory.
  • Mají lepší výkon při vkládání, přesouvání a extrakcitraczachycování prvků z libovolné pozice.
  • Std::list si také vede lépe s algoritmy, které tyto operace provádějí intenzivně.

S jasnými důvody je dalším krokem syntaxe, která deklaruje jeden.

Syntaxe seznamu

Chcete-li definovat std::list, musíme importovat hlavičkový soubor. Zde je syntaxe definice std::list:

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

Zde je popis výše uvedených parametrů:

  • T – Definuje typ obsaženého prvku. T můžete nahradit libovolným datovým typem, dokonce i uživatelem definovanými typy.
  • Alloc – Definuje typ objektu alokátoru. Ve výchozím nastavení se používá šablona třídy alokátoru. Je závislý na hodnotě a používá jednoduchý model alokace paměti.

Příklad 1

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

Výstup:

Výstup příkladu vytvoření a iterace std::list

Zde je snímek obrazovky kódu:

C++ kód pro vytvoření std::listu a jeho výpis pomocí cyklu for

Code Vysvětlení:

  1. Chcete-li používat jeho funkce, zahrňte soubor záhlaví algoritmu.
  2. Chcete-li používat jeho funkce, zahrňte soubor záhlaví iostream.
  3. Chcete-li používat jeho funkce, zahrňte soubor záhlaví seznamu.
  4. Zavolejte funkci main(). Programová logika by měla být přidána do těla této funkce.
  5. Vytvořte seznam s názvem můj_seznam se sadou 4 celých čísel.
  6. Použití pro smyčku vytvořit proměnnou cyklu x. Tato proměnná bude použita k iteraci prvků seznamu.
  7. Vytiskněte hodnoty seznamu na konzole.
  8. Konec těla smyčky for.
  9. Konec těla funkce main().

C++ Seznam funkcí

Zde jsou běžné funkce std::list:

funkce Description
vložit() Tato funkce vloží novou položku před pozici, na kterou ukazuje iterátor.
zatlačit zpátky() Tato funkce přidá novou položku na konec seznamu.
push_front() Přidá novou položku na začátek seznamu.
pop_front() Smaže první položku seznamu.
velikost() Tato funkce určuje počet prvků seznamu.
přední() To určuje první položky seznamu.
zadní() To určuje poslední položku seznamu.
zvrátit() Obrátí položky seznamu.
spojit() Sloučí dva seřazené seznamy.

Konstruktéři

Zde je seznam funkce poskytuje hlavičkový soubor:

  • Výchozí konstruktor std::list::list()- Vytvoří prázdný seznam, který nemá žádné prvky.
  • Konstruktor výplně std::list::list()- Vytvoří seznam s n prvky a každému prvku přiřadí hodnotu nula (0).
  • Konstruktor rozsahu std::list::list()- vytváří seznam s mnoha prvky v rozsahu od prvního do posledního.
  • Kopírovat konstruktor std::list::list()- Vytvoří seznam s kopií každého prvku obsaženého v existujícím seznamu.
  • Konstruktor přesunu std::list::list()- vytvoří seznam s prvky jiného seznamu pomocí sémantiky přesunu.
  • Konstruktor seznamu inicializátoru std::list::list()-Vytváří seznam s prvky jiného seznamu pomocí sémantiky přesunu.

Příklad 2

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

Výstup:

Výstup příkladu konstruktorů std::list

Zde je snímek obrazovky kódu:

C++ kód demonstrující konstruktory std::list default, range a move

Code Vysvětlení:

  1. Chcete-li používat jeho funkce, zahrňte soubor záhlaví iostream.
  2. Chcete-li používat jeho funkce, zahrňte soubor záhlaví seznamu.
  3. Zahrňte do kódu jmenný prostor std, abyste mohli používat jeho třídy bez jeho volání.
  4. Zavolejte funkci main(). Programová logika by měla být přidána do těla této funkce.
  5. Vytvořte prázdný seznam s názvem l.
  6. Vytvořte seznam s názvem l1 se sadou 3 celých čísel.
  7. Vytvořte seznam s názvem l2 se všemi prvky v seznamu s názvem l1, od začátku do konce.
  8. Vytvořte seznam s názvem l3 pomocí sémantiky přesunu. Seznam l3 bude mít stejný obsah jako seznam l2.
  9. Vytiskněte velikost seznamu s názvem l na konzole vedle jiného textu.
  10. Vytiskněte nějaký text na konzoli.
  11. Vytvořte iterátor s názvem a použijte jej k iteraci prvků seznamu s názvem l2.
  12. Vytiskněte prvky seznamu s názvem l2 na konzole.
  13. Vytiskněte nějaký text na konzoli.
  14. Vytvořte iterátor s názvem a použijte jej k iteraci prvků seznamu s názvem l3.
  15. Vytiskněte prvky seznamu s názvem l3 na konzole.
  16. Program musí po úspěšném dokončení vrátit hodnotu.
  17. Konec těla funkce main().

Vlastnosti kontejneru

Zde je seznam vlastností kontejneru:

Vlastnictví Description
Sekvence Sekvenční kontejnery seřadí své prvky v přísné lineární sekvenci. Prvky jsou přístupné podle jejich pozice v sekvenci.
Dvojitě propojený seznam Každý prvek obsahuje informace o tom, jak najít předchozí a následující prvky. To umožňuje konstantní čas pro operace vkládání a mazání.
Alokátor s vědomím Objekt alokátoru se používá pro dynamickou úpravu velikosti úložiště.

Vložení do seznamu

Existují různé funkce, které můžeme použít k vkládání hodnot do seznamu. Ukažme si to:

Příklad 3

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

Výstup:

Výstup po vložení prvků do std::list

Zde je snímek obrazovky kódu:

C++ kód používající push_front, push_back a insert na std::list

Code Vysvětlení:

  1. Chcete-li používat jeho funkce, zahrňte soubor záhlaví algoritmu.
  2. Chcete-li používat jeho funkce, zahrňte soubor záhlaví iostream.
  3. Chcete-li používat jeho funkce, zahrňte soubor záhlaví seznamu.
  4. Zavolejte funkci main(). Programová logika by měla být přidána do těla této funkce.
  5. Vytvořte seznam s názvem můj_seznam se sadou 4 celých čísel.
  6. Vložte prvek 11 na začátek seznamu s názvem my_list.
  7. Vložte prvek 18 na konec seznamu s názvem my_list.
  8. Vytvořte jej iterátor a použijte jej k nalezení prvku 10 ze seznamu my_list.
  9. Pomocí příkazu if určete, zda byl výše uvedený prvek nalezen nebo ne.
  10. Vložte prvek 21 před výše uvedený prvek, pokud byl nalezen.
  11. Konec těla příkazu if.
  12. Pomocí cyklu for vytvořte proměnnou x cyklu. Tato proměnná bude použita k iteraci prvků seznamu.
  13. Vytiskněte hodnoty seznamu na konzole.
  14. Konec těla smyčky for.
  15. Konec těla funkce main().

Prvky, které se nacházejí v seznamu, lze stejně snadno odstranit.

Smazání ze seznamu

Je možné smazat položky ze seznamu. Funkce erase() umožňuje smazat položku nebo rozsah položek ze seznamu.

  • Chcete-li odstranit jednu položku, jednoduše předáte jednu celočíselnou pozici. Položka bude smazána.
  • Chcete-li smazat rozsah, předáte počáteční a koncový iterátor. Ukažme si to.

Příklad 4

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

Výstup:

Výstup po odstranění prvku ze std::list

Zde je snímek obrazovky kódu:

C++ kód používající funkci erase na std::list

Code Vysvětlení:

  1. Chcete-li používat jeho funkce, zahrňte soubor záhlaví algoritmu.
  2. Chcete-li používat jeho funkce, zahrňte soubor záhlaví iostream.
  3. Chcete-li používat jeho funkce, zahrňte soubor záhlaví seznamu.
  4. Zahrňte do našeho programu jmenný prostor std, abyste mohli používat jeho třídy bez jeho volání.
  5. Zavolejte funkci main(). Programová logika by měla být přidána do těla této funkce.
  6. Vytvořte seznam s názvem můj_seznam se sadou 4 celých čísel.
  7. Vytiskněte nějaký text na konzoli.
  8. Pomocí cyklu for vytvořte proměnnou x cyklu. Tato proměnná bude použita k iteraci prvků seznamu.
  9. Vytiskněte hodnoty seznamu na konzole.
  10. Konec těla smyčky for.
  11. Vytvořte iterátor i, který ukazuje na první prvek seznamu.
  12. Použijte funkci erase() označenou iterátorem i.
  13. Vytiskněte nějaký text na konzoli.
  14. Pomocí cyklu for vytvořte proměnnou x cyklu. Tato proměnná bude použita k iteraci prvků seznamu.
  15. Vytiskněte hodnoty seznamu na konzole. To přichází po smazání.
  16. Konec těla smyčky for.
  17. Program musí po úspěšném dokončení vrátit hodnotu.
  18. Konec těla funkce main().

Nejčastější dotazy

std::vector ukládá prvky do souvislé paměti s náhodným přístupem O(1), zatímco std::list je dvojitě propojený seznam s možností vkládání nebo mazání O(1) kdekoli. Pro indexování zvolte vector a pro časté vkládání mezi prvky list.

Ne. std::list nemá operátor náhodného přístupu, takže list[2] se nekompiluje. K prvku se dostanete iterací od begin() nebo end() po jednom uzlu, což pro hlubokou pozici stojí lineární čas O(n).

std::list je dvojitě propojený seznam, který prochází oběma směry a podporuje funkci push_back. std::forward_list je jednoduše propojený seznam, který se pohybuje pouze vpřed, spotřebovává méně paměti na uzel a neposkytuje žádné iterátory size() ani reverzní iterátory.

Zavolejte členskou funkci my_list.sort(), která běží přibližně za N log N a udržuje stejné prvky stabilní. Algoritmus std::sort nebude fungovat, protože potřebuje iterátory s náhodným přístupem. Pro sestupné seřazení předejte funkci sort() funkci std::greater.

Vložení nebo smazání uzlu je konstantní čas O(1), jakmile je iterátor držen na dané pozici, protože se mění pouze sousední ukazatele. Nalezení dané pozice pomocí traversalu stále stojí čas O(n).

Ano. std::list není množina, takže volně ukládá opakované hodnoty. Každý příkaz push_back, push_front nebo insert přidá nový uzel bez ohledu na existující obsah. Použijte std::set, když potřebujete odmítnout duplicitní prvky.

Ano. GitHub Copilot zapisuje deklarace std::list, iterační smyčky a vkládá nebo mazá volání z krátkého komentáře nebo názvu funkce. Často doporučuje std::vector, když souvislé úložiště lépe vyhovuje danému úkolu.

Asistenti pro kódování s umělou inteligencí automaticky dokončují kód kontejneru STL, označují nesprávné použití iterátoru, převádějí std::list na std::vector a vysvětlují kompromisy v oblasti složitosti. Urychlují učení se STL, i když každý návrh je stále třeba přezkoumat.

Shrňte tento příspěvek takto: