std::list in C++ με Παράδειγμα

⚡ Έξυπνη Σύνοψη

std::list in C++ είναι ένα κοντέινερ ακολουθίας που υλοποιείται ως διπλά συνδεδεμένη λίστα, επιτρέποντας γρήγορη εισαγωγή και διαγραφή σε οποιαδήποτε θέση, ενώ αποθηκεύει στοιχεία σε μη συνεχόμενη μνήμη και υποστηρίζει αμφίδρομη διαδοχική πρόσβαση αντί για τυχαία πρόσβαση.

  • 🔗 Διπλά συνδεδεμένη λίστα: Κάθε στοιχείο διατηρεί συνδέσμους προς τον προηγούμενο και τον επόμενο κόμβο του, επομένως τα δεδομένα std::list αποθηκεύονται σε μη συνεχόμενη μνήμη.
  • Γρήγορη εισαγωγή και διαγραφή: Η προσθήκη ή η αφαίρεση ενός στοιχείου σε μια γνωστή θέση είναι σταθερής χρονικής διάρκειας, σε αντίθεση με ένα διάνυσμα που μετατοπίζει στοιχεία.
  • 🚫 Δεν υπάρχει τυχαία πρόσβαση: Τα στοιχεία προσεγγίζονται με διαδοχική διέλευση από οποιοδήποτε άκρο, επομένως η δημιουργία ευρετηρίου όπως η λίστα[3] ​​δεν είναι διαθέσιμη.
  • 🧩 Κατασκευαστές: Οι κατασκευαστές προεπιλεγμένης λίστας, λίστας συμπλήρωσης, λίστας εύρους, λίστας αντιγραφής, λίστας μετακίνησης και λίστας αρχικοποίησης δημιουργούν μια λίστα std::list με διαφορετικούς τρόπους.
  • Λειτουργίες μελών: Οι push_front(), push_back(), insert(), erase(), size(), reverse() και merge() διαχειρίζονται τα περιεχόμενα της λίστας.
  • 🤖 Βοήθεια AI: Το GitHub Copilot και παρόμοιοι βοηθοί υποστηρίζονται από δηλώσεις std::list, επαναλήπτες και εισάγουν ή διαγράφουν λογική από ένα σύντομο σχόλιο.

std::list in C++

Τι είναι το std::list;

In C++, το std::list αναφέρεται σε ένα κοντέινερ αποθήκευσης. Το std::list σάς επιτρέπει να εισάγετε και να αφαιρείτε στοιχεία από οπουδήποτε. Το std::list υλοποιείται ως διπλά συνδεδεμένη λίστα. Αυτό σημαίνει ότι τα δεδομένα της λίστας είναι προσβάσιμα αμφίδρομα και διαδοχικά.

Η λίστα της Βασικής Βιβλιοθήκης Προτύπων δεν υποστηρίζει γρήγορη τυχαία πρόσβαση, αλλά υποστηρίζει διαδοχική πρόσβαση από όλες τις κατευθύνσεις.

Μπορείτε να διασκορπίσετε στοιχεία λίστας σε διαφορετικά κομμάτια μνήμης. Οι πληροφορίες που απαιτούνται για τη διαδοχική πρόσβαση στα δεδομένα αποθηκεύονται σε ένα κοντέινερ. Η λίστα std:: μπορεί να επεκταθεί και να συρρικνωθεί και από τα δύο άκρα όπως απαιτείται κατά τη διάρκεια του χρόνου εκτέλεσης. Ένας εσωτερικός κατανεμητής πληροί αυτόματα τις απαιτήσεις αποθήκευσης.

Αυτά τα χαρακτηριστικά εγείρουν ένα πρακτικό ερώτημα: πότε πρέπει πραγματικά να αναζητήσετε μια λίστα;

Γιατί να χρησιμοποιήσετε το std::list;

Ακολουθούν οι λόγοι για τη χρήση του std::list:

  • Το std::list αποδίδει καλύτερα σε σύγκριση με άλλα κοντέινερ ακολουθίας όπως ο πίνακας και το διάνυσμα.
  • Έχουν καλύτερη απόδοση στην εισαγωγή, την κίνηση και την εξαγωγή.tracστοιχεία από οποιαδήποτε θέση.
  • Το std::list τα πάει καλύτερα με αλγόριθμους που εκτελούν εντατικά τέτοιες λειτουργίες.

Με σαφείς τους λόγους, το επόμενο βήμα είναι η σύνταξη που δηλώνει ένα.

Σύνταξη λίστας

Για να ορίσουμε τη λίστα std:: πρέπει να εισάγουμε το αρχείο κεφαλίδας. Εδώ είναι η σύνταξη ορισμού std::list:

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

Ακολουθεί μια περιγραφή των παραπάνω παραμέτρων:

  • T – Ορίζει τον τύπο του στοιχείου που περιέχεται. Μπορείτε να αντικαταστήσετε το T με οποιονδήποτε τύπο δεδομένων, ακόμα και με τύπους που ορίζονται από τον χρήστη.
  • Alloc – Ορίζει τον τύπο του αντικειμένου allocator. Αυτό χρησιμοποιεί το πρότυπο κλάσης allocator από προεπιλογή. Εξαρτάται από την τιμή και χρησιμοποιεί ένα απλό μοντέλο κατανομής μνήμης.

Παράδειγμα 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';
	}
}

Παραγωγή:

Έξοδος του παραδείγματος δημιουργίας και επανάληψης std::list

Εδώ είναι ένα στιγμιότυπο οθόνης του κώδικα:

C++ κώδικας που δημιουργεί μια std::list και την εκτύπωσή της με έναν βρόχο for

Code Επεξήγηση:

  1. Συμπεριλάβετε το αρχείο κεφαλίδας αλγορίθμου για να χρησιμοποιήσετε τις συναρτήσεις του.
  2. Συμπεριλάβετε το αρχείο κεφαλίδας iostream για να χρησιμοποιήσετε τις λειτουργίες του.
  3. Συμπεριλάβετε το αρχείο κεφαλίδας λίστας για να χρησιμοποιήσετε τις λειτουργίες του.
  4. Καλέστε τη συνάρτηση main(). Η λογική του προγράμματος πρέπει να προστεθεί στο σώμα αυτής της συνάρτησης.
  5. Δημιουργήστε μια λίστα με το όνομα my_list με ένα σύνολο 4 ακεραίων.
  6. Χρήση για βρόχο για να δημιουργήσετε μια μεταβλητή βρόχου x. Αυτή η μεταβλητή θα χρησιμοποιηθεί για την επανάληψη των στοιχείων της λίστας.
  7. Εκτυπώστε τις τιμές της λίστας στην κονσόλα.
  8. Τέλος του σώματος του βρόχου for.
  9. Τέλος του σώματος της συνάρτησης main().

C++ Λειτουργίες λίστας

Εδώ είναι οι κοινές συναρτήσεις std::list:

Λειτουργία Περιγραφή
εισάγετε() Αυτή η συνάρτηση εισάγει ένα νέο στοιχείο πριν από τη θέση που δείχνει ο επαναλήπτης.
push_back() Αυτή η λειτουργία προσθέτει ένα νέο στοιχείο στο τέλος της λίστας.
push_front() Προσθέτει ένα νέο στοιχείο στο μπροστινό μέρος της λίστας.
pop_front() Διαγράφει το πρώτο στοιχείο της λίστας.
Μέγεθος() Αυτή η συνάρτηση καθορίζει τον αριθμό των στοιχείων της λίστας.
εμπρός() Καθορίζει τα πρώτα στοιχεία της λίστας.
πίσω() To καθορίζει το τελευταίο στοιχείο της λίστας.
ΑΝΤΙΣΤΡΟΦΗ() Αντιστρέφει τα στοιχεία της λίστας.
συγχώνευση() Συγχωνεύει δύο ταξινομημένες λίστες.

Κατασκευαστές

Εδώ είναι η λίστα των λειτουργίες παρέχεται από το αρχείο κεφαλίδας:

  • Προεπιλεγμένος κατασκευαστής std::list::list()- Δημιουργεί μια κενή λίστα, αυτή, με μηδενικά στοιχεία.
  • Συμπληρώστε τον κατασκευαστή std::list::list()- Δημιουργεί μια λίστα με n στοιχεία και εκχωρεί μια τιμή μηδέν (0) σε κάθε στοιχείο.
  • Κατασκευαστής εύρους std::list::list()- δημιουργεί μια λίστα με πολλά στοιχεία στην περιοχή από το πρώτο έως το τελευταίο.
  • Αντιγραφή κατασκευαστή std::list::list()- Δημιουργεί μια λίστα με ένα αντίγραφο κάθε στοιχείου που περιέχεται στην υπάρχουσα λίστα.
  • Move constructor std::list::list()- δημιουργεί μια λίστα με τα στοιχεία μιας άλλης λίστας χρησιμοποιώντας τη σημασιολογία κίνησης.
  • Κατασκευαστής λίστας Initializer std::list::list()-Δημιουργεί μια λίστα με τα στοιχεία μιας άλλης λίστας χρησιμοποιώντας τη σημασιολογία κίνησης.

Παράδειγμα 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;
}

Παραγωγή:

Έξοδος του παραδείγματος κατασκευαστών std::list

Εδώ είναι ένα στιγμιότυπο οθόνης του κώδικα:

C++ κώδικας που παρουσιάζει τους κατασκευαστές std::list default, range και move

Code Επεξήγηση:

  1. Συμπεριλάβετε το αρχείο κεφαλίδας iostream για να χρησιμοποιήσετε τις λειτουργίες του.
  2. Συμπεριλάβετε το αρχείο κεφαλίδας λίστας για να χρησιμοποιήσετε τις λειτουργίες του.
  3. Συμπεριλάβετε τον χώρο ονομάτων std στον κώδικα για να χρησιμοποιήσετε τις κλάσεις του χωρίς να τον καλέσετε.
  4. Καλέστε τη συνάρτηση main(). Η λογική του προγράμματος πρέπει να προστεθεί στο σώμα αυτής της συνάρτησης.
  5. Δημιουργήστε μια κενή λίστα με το όνομα l.
  6. Δημιουργήστε μια λίστα με το όνομα l1 με ένα σύνολο 3 ακεραίων.
  7. Δημιουργήστε μια λίστα με το όνομα l2 με όλα τα στοιχεία της λίστας με το όνομα l1, από την αρχή μέχρι το τέλος.
  8. Δημιουργήστε μια λίστα με το όνομα l3 χρησιμοποιώντας τη σημασιολογία κίνησης. Η λίστα l3 θα έχει τα ίδια περιεχόμενα με τη λίστα l2.
  9. Εκτυπώστε το μέγεθος της λίστας με το όνομα l στην κονσόλα μαζί με άλλο κείμενο.
  10. Εκτυπώστε λίγο κείμενο στην κονσόλα.
  11. Δημιουργήστε έναν επαναλήπτη με το όνομά του και χρησιμοποιήστε τον για να επαναλάβετε τα στοιχεία της λίστας με το όνομα l2.
  12. Εκτυπώστε τα στοιχεία της λίστας με το όνομα l2 στην κονσόλα.
  13. Εκτυπώστε λίγο κείμενο στην κονσόλα.
  14. Δημιουργήστε έναν επαναλήπτη με το όνομά του και χρησιμοποιήστε τον για να επαναλάβετε τα στοιχεία της λίστας με το όνομα l3.
  15. Εκτυπώστε τα στοιχεία της λίστας με το όνομα l3 στην κονσόλα.
  16. Το πρόγραμμα πρέπει να επιστρέψει τιμή μετά την επιτυχή ολοκλήρωση.
  17. Τέλος του σώματος της συνάρτησης main().

Ιδιότητες κοντέινερ

Ακολουθεί η λίστα με τις ιδιότητες του κοντέινερ:

Ιδιοκτησία Περιγραφή
Ακολουθία Τα δοχεία ακολουθίας ταξινομούν τα στοιχεία τους σε μια αυστηρή γραμμική ακολουθία. Τα στοιχεία είναι προσβάσιμα από τη θέση τους στην ακολουθία.
Λίστα με διπλή σύνδεση Κάθε στοιχείο έχει πληροφορίες για τον εντοπισμό προηγούμενων και επόμενων στοιχείων. Αυτό επιτρέπει σταθερό χρόνο για τις λειτουργίες εισαγωγής και διαγραφής.
Ενημερωμένος κατανεμητής Ένα αντικείμενο κατανομής χρησιμοποιείται για την δυναμική τροποποίηση του μεγέθους αποθήκευσης.

Εισαγωγή σε λίστα

Υπάρχουν διαφορετικές συναρτήσεις που μπορούμε να χρησιμοποιήσουμε για να εισάγουμε τιμές σε μια λίστα. Ας το δείξουμε αυτό:

Παράδειγμα 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';
	}
}

Παραγωγή:

Έξοδος μετά την εισαγωγή στοιχείων σε ένα std::list

Εδώ είναι ένα στιγμιότυπο οθόνης του κώδικα:

C++ κώδικα χρησιμοποιώντας push_front, push_back και insert σε ένα std::list

Code Επεξήγηση:

  1. Συμπεριλάβετε το αρχείο κεφαλίδας αλγορίθμου για να χρησιμοποιήσετε τις συναρτήσεις του.
  2. Συμπεριλάβετε το αρχείο κεφαλίδας iostream για να χρησιμοποιήσετε τις λειτουργίες του.
  3. Συμπεριλάβετε το αρχείο κεφαλίδας λίστας για να χρησιμοποιήσετε τις λειτουργίες του.
  4. Καλέστε τη συνάρτηση main(). Η λογική του προγράμματος πρέπει να προστεθεί στο σώμα αυτής της συνάρτησης.
  5. Δημιουργήστε μια λίστα με το όνομα my_list με ένα σύνολο 4 ακεραίων.
  6. Εισαγάγετε το στοιχείο 11 στο μπροστινό μέρος της λίστας με το όνομα my_list.
  7. Εισαγάγετε το στοιχείο 18 στο τέλος της λίστας με το όνομα my_list.
  8. Δημιουργήστε έναν επαναλήπτη και χρησιμοποιήστε τον για να βρείτε το στοιχείο 10 από τη λίστα my_list.
  9. Χρησιμοποιήστε μια δήλωση if για να προσδιορίσετε εάν το παραπάνω στοιχείο βρέθηκε ή όχι.
  10. Εισαγάγετε το στοιχείο 21 πριν από το παραπάνω στοιχείο εάν βρέθηκε.
  11. Τέλος του σώματος της δήλωσης if.
  12. Χρησιμοποιήστε έναν βρόχο for για να δημιουργήσετε μια μεταβλητή βρόχου x. Αυτή η μεταβλητή θα χρησιμοποιηθεί για επανάληψη πάνω από τα στοιχεία της λίστας.
  13. Εκτυπώστε τις τιμές της λίστας στην κονσόλα.
  14. Τέλος του σώματος του βρόχου for.
  15. Τέλος του σώματος της συνάρτησης main().

Τα στοιχεία που περιλαμβάνονται σε μια λίστα μπορούν εξίσου εύκολα να αφαιρεθούν.

Διαγραφή από λίστα

Είναι δυνατή η διαγραφή στοιχείων από μια λίστα. Η συνάρτηση erase() σάς επιτρέπει να διαγράψετε ένα στοιχείο ή μια περιοχή στοιχείων από μια λίστα.

  • Για να διαγράψετε ένα μεμονωμένο στοιχείο, περνάτε απλώς μια θέση ακέραιου αριθμού. Το στοιχείο θα διαγραφεί.
  • Για να διαγράψετε ένα εύρος, περνάτε τον αρχικό και τον τελικό επαναλήπτη. Ας το δείξουμε αυτό.

Παράδειγμα 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;
}

Παραγωγή:

Έξοδος μετά τη διαγραφή ενός στοιχείου από μια std::list

Εδώ είναι ένα στιγμιότυπο οθόνης του κώδικα:

C++ κώδικας χρησιμοποιώντας τη συνάρτηση erase σε μια std::list

Code Επεξήγηση:

  1. Συμπεριλάβετε το αρχείο κεφαλίδας αλγορίθμου για να χρησιμοποιήσετε τις συναρτήσεις του.
  2. Συμπεριλάβετε το αρχείο κεφαλίδας iostream για να χρησιμοποιήσετε τις λειτουργίες του.
  3. Συμπεριλάβετε το αρχείο κεφαλίδας λίστας για να χρησιμοποιήσετε τις λειτουργίες του.
  4. Συμπεριλάβετε τον χώρο ονομάτων std στο πρόγραμμά μας για να χρησιμοποιήσετε τις κλάσεις του χωρίς να τον καλέσετε.
  5. Καλέστε τη συνάρτηση main(). Η λογική του προγράμματος πρέπει να προστεθεί στο σώμα αυτής της συνάρτησης.
  6. Δημιουργήστε μια λίστα με το όνομα my_list με ένα σύνολο 4 ακεραίων.
  7. Εκτυπώστε λίγο κείμενο στην κονσόλα.
  8. Χρησιμοποιήστε έναν βρόχο for για να δημιουργήσετε μια μεταβλητή βρόχου x. Αυτή η μεταβλητή θα χρησιμοποιηθεί για επανάληψη πάνω από τα στοιχεία της λίστας.
  9. Εκτυπώστε τις τιμές της λίστας στην κονσόλα.
  10. Τέλος του σώματος του βρόχου for.
  11. Δημιουργήστε έναν επαναλήπτη i που να οδηγεί στο πρώτο στοιχείο της λίστας.
  12. Χρησιμοποιήστε τη συνάρτηση erase() που επισημαίνεται από τον επαναλήπτη i.
  13. Εκτυπώστε λίγο κείμενο στην κονσόλα.
  14. Χρησιμοποιήστε έναν βρόχο for για να δημιουργήσετε μια μεταβλητή βρόχου x. Αυτή η μεταβλητή θα χρησιμοποιηθεί για επανάληψη πάνω από τα στοιχεία της λίστας.
  15. Εκτυπώστε τις τιμές της λίστας στην κονσόλα. Αυτό έρχεται μετά τη διαγραφή.
  16. Τέλος του σώματος του βρόχου for.
  17. Το πρόγραμμα πρέπει να επιστρέψει μια τιμή μετά την επιτυχή ολοκλήρωση.
  18. Τέλος του σώματος της συνάρτησης main().

Συχνές Ερωτήσεις

Η std::vector αποθηκεύει στοιχεία σε συνεχή μνήμη με τυχαία προσπέλαση O(1), ενώ η std::list είναι μια διπλά συνδεδεμένη λίστα που δίνει εισαγωγή ή διαγραφή O(1) οπουδήποτε. Επιλέξτε vector για ευρετηρίαση και list για συχνές ενδιάμεσες εισαγωγές.

Όχι. Η std::list δεν έχει τελεστή τυχαίας πρόσβασης, επομένως η list[2] δεν μεταγλωττίζεται. Φτάνετε σε ένα στοιχείο επαναλαμβάνοντας από την begin() ή την end() έναν κόμβο κάθε φορά, κάτι που κοστίζει γραμμικό χρόνο O(n) για μια βαθιά θέση.

Η std::list είναι μια διπλά συνδεδεμένη λίστα που κινείται και στις δύο κατευθύνσεις και υποστηρίζει την push_back. Η std::forward_list είναι μια μονά συνδεδεμένη λίστα που κινείται μόνο προς τα εμπρός, χρησιμοποιεί λιγότερη μνήμη ανά κόμβο και δεν παρέχει size() ή αντίστροφους επαναλήπτες.

Καλέστε τη συνάρτηση-μέλος my_list.sort(), η οποία εκτελείται σε περίπου N log N και διατηρεί σταθερά τα ίσα στοιχεία. Ο αλγόριθμος std::sort δεν θα λειτουργήσει επειδή χρειάζεται επαναλήπτες τυχαίας πρόσβασης. Μεταβιβάστε την std::greater στην sort() για φθίνουσα σειρά.

Η εισαγωγή ή η διαγραφή ενός κόμβου είναι σταθερή σε χρόνο O(1) από τη στιγμή που κρατάτε έναν επαναλήπτη στη θέση του, επειδή μόνο οι γειτονικοί δείκτες αλλάζουν. Η εύρεση αυτής της θέσης πρώτα μέσω διάσχισης εξακολουθεί να κοστίζει χρόνο O(n).

Ναι. Μια std::list δεν είναι σύνολο, επομένως αποθηκεύει επαναλαμβανόμενες τιμές ελεύθερα. Κάθε push_back, push_front ή insert προσθέτει έναν νέο κόμβο ανεξάρτητα από τα υπάρχοντα περιεχόμενα. Χρησιμοποιήστε το std::set όταν χρειάζεται να απορρίψετε διπλότυπα στοιχεία.

Ναί. GitHub Copilot γράφει δηλώσεις std::list, επαναλαμβανόμενους βρόχους και εισάγει ή διαγράφει κλήσεις από ένα σύντομο σχόλιο ή όνομα συνάρτησης. Συχνά προτείνει std::vector όταν η συνεχής αποθήκευση ταιριάζει καλύτερα στην εργασία.

Οι βοηθοί κωδικοποίησης τεχνητής νοημοσύνης συμπληρώνουν αυτόματα τον κώδικα κοντέινερ STL, επισημαίνουν λανθασμένη χρήση επαναληπτών, μετατρέπουν ένα std::list σε std::vector και εξηγούν τους συμβιβασμούς πολυπλοκότητας. Επιταχύνουν την εκμάθηση του STL, αν και κάθε πρόταση χρειάζεται ακόμη αναθεώρηση.

Συνοψίστε αυτήν την ανάρτηση με: