std::list in C++ példával

⚡ Okos összefoglaló

std::list in C++ egy kétszeresen láncolt listaként megvalósított szekvenciakonténer, amely lehetővé teszi a gyors beszúrást és törlést bármely pozícióban, miközben az elemeket nem összefüggő memóriában tárolja, és a véletlenszerű hozzáférés helyett kétirányú szekvenciális hozzáférést támogat.

  • 🔗 Duplán láncolt lista: Minden elem linkeket tart fenn az előző és a következő csomóponthoz, így az std::list adatok nem összefüggő memóriában tárolódnak.
  • Gyors beszúrás és törlés: Egy elem hozzáadása vagy eltávolítása egy ismert pozícióban állandó idő, ellentétben egy vektorral, amely eltolja az elemeket.
  • ???? Nincs véletlenszerű hozzáférés: Az elemeket mindkét végről szekvenciális bejárással érjük el, így az olyan indexelés, mint a list[3], nem érhető el.
  • 🧩 Kivitelezők: A default, fill, range, copy, move és initializer-list konstruktorok különböző módokon építik fel az std::list listát.
  • 🇧🇷 Tagok funkciói: A push_front(), push_back(), insert(), erase(), size(), reverse() és merge() függvények kezelik a lista tartalmát.
  • 🤖 AI segítség: A GitHub Copilot és hasonló asszisztensek scaffoldingot biztosítanak a std::list deklarációkhoz, iterátorokhoz, valamint logikát szúrnak be vagy törölnek egy rövid megjegyzésből.

std::list in C++

Mi az std::list?

In C++, az std::list egy tárolókonténerre utal. Az std::list lehetővé teszi elemek beszúrását és eltávolítását bárhonnan. Az std::list duplán linkelt listaként van megvalósítva. Ez azt jelenti, hogy a listaadatok kétirányúan és szekvenciálisan érhetők el.

A Standard Template Library lista nem támogatja a gyors véletlenszerű hozzáférést, de támogatja a szekvenciális hozzáférést minden irányból.

A listaelemeket szétszórhatja különböző memóriadarabokban. Az adatok szekvenciális eléréséhez szükséges információkat egy tárolóban tárolják. Az std::list mindkét végéről szükség szerint bővülhet és zsugorodhat futás közben. A belső elosztó automatikusan teljesíti a tárolási követelményeket.

Ezek a tulajdonságok egy gyakorlati kérdést vetnek fel: mikor kell valójában listához nyúlni?

Miért érdemes az std::list-et használni?

Íme az std::list használatának okai:

  • Az std::list jobban teljesít más szekvenciatárolókhoz, mint például az array és a vector.
  • Jobb teljesítményt nyújtanak a behelyezés, mozgatás és kijuttatás terén.tracelemek bármilyen pozícióból.
  • Az std::list az ilyen műveleteket intenzíven végrehajtó algoritmusokkal is jobban teljesít.

Miután az okok tisztázódtak, a következő lépés a deklaráló szintaxis.

Lista szintaxis

Az std::list meghatározásához importálnunk kell a fejléc fájl. Íme az std::list definíció szintaxisa:

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

Itt található a fenti paraméterek leírása:

  • T – Meghatározza a benne foglalt elem típusát. A T-t bármilyen adattípussal helyettesítheti, akár felhasználó által definiált típusokkal is.
  • Alloc – Meghatározza az allokátor objektum típusát. Ez alapértelmezés szerint az allokátor osztálysablont használja. Értékfüggő és egy egyszerű memória-allokációs modellt használ.

Példa 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';
	}
}

output:

Az std::list létrehozási és iterációs példa kimenete

Itt van egy képernyőkép a kódról:

C++ kód, amely létrehoz egy std::list-et és kinyomtatja egy for ciklussal

Code Magyarázat:

  1. Tartalmazza az algoritmus fejlécfájlját a funkcióinak használatához.
  2. Tartalmazza az iostream fejlécfájlt a funkcióinak használatához.
  3. Tartalmazza a listafejléc fájlt a funkcióinak használatához.
  4. Hívja meg a main() függvényt. A program logikáját hozzá kell adni a függvény törzséhez.
  5. Hozzon létre egy listát my_list néven 4 egész szám halmazával.
  6. Használat hurokhoz egy x ciklusváltozó létrehozása. Ezt a változót fogjuk használni a listaelemek végigjárására.
  7. Nyomtassa ki a lista értékeit a konzolon.
  8. A for ciklus törzsének vége.
  9. A main() függvény törzsének vége.

C++ Funkciók listája

Íme a gyakori std::list függvények:

Funkció Leírás
beillesztés () Ez a funkció egy új elemet szúr be az iterátor által mutatott pozíció elé.
visszavet() Ez a funkció új elemet ad a lista végére.
push_front() Új elemet ad a lista elejére.
pop_front() Törli a lista első elemét.
méret () Ez a függvény határozza meg a listaelemek számát.
elülső() Meghatározza a lista első elemeit.
vissza() A lista utolsó elemét határozza meg.
fordított () Megfordítja a listaelemeket.
összeolvad() Két rendezett listát egyesít.

Konstruktorok

Itt van a lista funkciók által biztosított fejléc fájl:

  • Alapértelmezett konstruktor std::list::list()- Egy üres listát hoz létre, amely nulla elemmel.
  • Fill konstruktor std::list::list()- Létrehoz egy listát n elemből, és minden elemhez nulla (0) értéket rendel.
  • Tartománykonstruktor std::list::list()- olyan listát hoz létre, amely sok elemet tartalmaz az elsőtől az utolsóig terjedő tartományban.
  • Konstruktor másolása std::list::list()- Létrehoz egy listát a meglévő lista minden elemének másolatával.
  • Move konstruktor std::list::list()- egy listát hoz létre egy másik lista elemeivel a mozgatási szemantika segítségével.
  • Inicializáló listakonstruktor std::list::list()-Létrehoz egy listát egy másik lista elemeivel a mozgatási szemantika segítségével.

Példa 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;
}

output:

Az std::list konstruktorok példájának kimenete

Itt van egy képernyőkép a kódról:

C++ std::list default, range és move konstruktorokat bemutató kód

Code Magyarázat:

  1. Tartalmazza az iostream fejlécfájlt a funkcióinak használatához.
  2. Tartalmazza a listafejléc fájlt a funkcióinak használatához.
  3. Szerelje be az std névteret a kódba, hogy az osztályait hívás nélkül használja.
  4. Hívja meg a main() függvényt. A program logikáját hozzá kell adni a függvény törzséhez.
  5. Hozzon létre egy üres listát l néven.
  6. Hozzon létre egy l1 nevű listát 3 egész szám halmazával.
  7. Hozzon létre egy l2 nevű listát az l1 nevű lista minden elemével az elejétől a végéig.
  8. Hozzon létre egy l3 nevű listát a mozgatási szemantika segítségével. Az l3 lista tartalma megegyezik az l2 listával.
  9. Nyomtassa ki az l nevű lista méretét a konzolon a többi szöveg mellé.
  10. Nyomtasson szöveget a konzolra.
  11. Hozzon létre egy iterátor nevű iterátort, és használja azt az l2 nevű lista elemei közötti iterációhoz.
  12. Nyomtassa ki az l2 nevű lista elemeit a konzolon.
  13. Nyomtasson szöveget a konzolra.
  14. Hozzon létre egy iterátor nevű iterátort, és használja azt az l3 nevű lista elemei közötti iterációhoz.
  15. Nyomtassa ki az l3 nevű lista elemeit a konzolon.
  16. A programnak értéket kell visszaadnia a sikeres befejezés után.
  17. A main() függvény törzsének vége.

Konténer tulajdonságai

Íme a tároló tulajdonságainak listája:

Ingatlanok Leírás
Sorozat A szekvenciatárolók elemeiket szigorú lineáris sorrendbe rendezik. Az elemek a sorrendben elfoglalt helyük alapján érhetők el.
Duplán linkelt lista Minden elem rendelkezik információkkal az előző és a következő elemek megkereséséhez. Ez állandó időt biztosít a beillesztési és törlési műveletekhez.
Kiosztó-tudatos Egy allokátor objektum a tárolóméret dinamikus módosítására szolgál.

Beszúrás egy listába

Különböző függvényekkel tudunk értékeket beszúrni egy listába. Nézzük meg ezt:

Példa 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';
	}
}

output:

Kimenet elemek std::list-be való beszúrása után

Itt van egy képernyőkép a kódról:

C++ kód push_front, push_back és insert használatával egy std::list-en

Code Magyarázat:

  1. Tartalmazza az algoritmus fejlécfájlját a funkcióinak használatához.
  2. Tartalmazza az iostream fejlécfájlt a funkcióinak használatához.
  3. Tartalmazza a listafejléc fájlt a funkcióinak használatához.
  4. Hívja meg a main() függvényt. A program logikáját hozzá kell adni a függvény törzséhez.
  5. Hozzon létre egy listát my_list néven 4 egész szám halmazával.
  6. Illessze be a 11-es elemet a my_list nevű lista elejére.
  7. Szúrja be a 18-as elemet a my_list nevű lista végére.
  8. Hozzon létre egy iterátort, és keresse meg vele a 10-es elemet a my_list listából.
  9. Használjon if utasítást annak meghatározására, hogy a fenti elem megtalálható-e vagy sem.
  10. Szúrja be a 21-es elemet a fenti elem elé, ha megtalálta.
  11. Az if utasítás törzsének vége.
  12. Használja a for ciklust egy x ciklusváltozó létrehozásához. Ez a változó a listaelemek közötti iterációra szolgál.
  13. Nyomtassa ki a lista értékeit a konzolon.
  14. A for hurok törzsének vége.
  15. A main() függvény törzsének vége.

A listába kerülő elemek ugyanolyan könnyen eltávolíthatók.

Törlés listából

Lehetséges elemeket törölni egy listából. Az erase() függvény lehetővé teszi egy elem vagy elemtartomány törlését egy listából.

  • Egyetlen elem törléséhez egyszerűen adjon meg egy egész számot. Az elem törlésre kerül.
  • Egy tartomány törléséhez átadjuk a kezdő és a záró iterátorokat. Nézzük meg ezt.

Példa 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;
}

output:

Kimenet egy elem törlése után egy std::list-ből

Itt van egy képernyőkép a kódról:

C++ kód az erase függvény használatával egy std::list-en

Code Magyarázat:

  1. Tartalmazza az algoritmus fejlécfájlját a funkcióinak használatához.
  2. Tartalmazza az iostream fejlécfájlt a funkcióinak használatához.
  3. Tartalmazza a listafejléc fájlt a funkcióinak használatához.
  4. Szerelje be az std névteret a programunkba, hogy az osztályait hívás nélkül használhassa.
  5. Hívja meg a main() függvényt. A program logikáját hozzá kell adni a függvény törzséhez.
  6. Hozzon létre egy listát my_list néven 4 egész szám halmazával.
  7. Nyomtasson szöveget a konzolra.
  8. Használja a for ciklust egy x ciklusváltozó létrehozásához. Ez a változó a listaelemek közötti iterációra szolgál.
  9. Nyomtassa ki a lista értékeit a konzolon.
  10. A for ciklus törzsének vége.
  11. Hozzon létre egy iterátort i, amely a lista első elemére mutat.
  12. Használja az erase() függvényt, amelyet az iterátor i.
  13. Nyomtasson szöveget a konzolra.
  14. Használja a for ciklust egy x ciklusváltozó létrehozásához. Ez a változó a listaelemek közötti iterációra szolgál.
  15. Nyomtassa ki a lista értékeit a konzolon. Ez a törlés után következik be.
  16. A for ciklus törzsének vége.
  17. A programnak értéket kell visszaadnia a sikeres befejezés után.
  18. A main() függvény törzsének vége.

GYIK

Az std::vector elemei összefüggő memóriában tárolódnak O(1) véletlenszerű eléréssel, míg az std::list egy duplán láncolt lista, amely O(1) beszúrást vagy törlést tesz lehetővé bárhol. Válasszon vektort az indexeléshez, és listát a gyakori középső beszúrásokhoz.

Nem. Az std::list függvénynek nincs véletlen elérésű operátora, így a list[2] nem fordul le. Egy elemhez a begin() vagy end() függvényből csomópontonkénti iterációval jutunk el, ami egy mély pozíció eléréséhez lineáris O(n) időbe telik.

Az std::list egy kétszeresen láncolt lista, amely mindkét irányban halad, és támogatja a push_back metódust. Az std::forward_list egy egyszeresen láncolt lista, amely csak előre mozog, kevesebb memóriát használ csomópontonként, és nem biztosít size() vagy fordított iterátorokat.

Hívjuk meg a my_list.sort() tagfüggvényt, amely körülbelül N log N idő alatt fut le, és az egyenlő elemeket stabilan tartja. Az std::sort algoritmus nem fog működni, mert véletlen hozzáférésű iterátorokat igényel. Adjuk át az std::greater függvényt a sort()-nak a csökkenő sorrendhez.

Egy csomópont beszúrása vagy törlése konstans O(1) idő alatt történik, miután egy iterátort a pozíción tartottunk, mivel csak a szomszédos mutatók változnak. A pozíció első bejárással történő megtalálása továbbra is O(n) időbe kerül.

Igen. Egy std::list nem egy halmaz, tehát szabadon tárolja az ismétlődő értékeket. Minden push_back, push_front vagy insert parancs új csomópontot ad hozzá a meglévő tartalomtól függetlenül. Használd az std::set függvényt, ha el kell utasítanod az ismétlődő elemeket.

Igen. GitHub másodpilóta std::list deklarációkat, iterátor ciklusokat ír, valamint beszúr vagy töröl hívásokat hajt végre egy rövid megjegyzés vagy függvénynév alapján. Gyakran javasolja az std::vector használatát, ha a folyamatos tárolás jobban megfelel a feladatnak.

A mesterséges intelligencia által vezérelt kódolási asszisztensek automatikusan kiegészítik az STL konténerkódot, jelzik a helytelen iterátorhasználatot, std::listákat std::vektorokká konvertálnak, és elmagyarázzák a bonyolultsággal járó kompromisszumokat. Felgyorsítják az STL tanulását, bár minden javaslatot felül kell vizsgálni.

Foglald össze ezt a bejegyzést a következőképpen: