Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision |
cpp:stl:containers [2020/05/30 19:12] – gthanos | cpp:stl:containers [2021/06/06 07:42] – [Προσδιορισμός εύρους στοιχείων] gthanos |
---|
* **Sequence containers:** Αποθηκεύουν τα δεδομένα σειριακά, οδηγώντας σε χρόνους αναζήτησης γραμμικούς στο μέγεθος του πλήθους των στοιχείων που είναι αποθηκευμένα. Παραδείγματα τέτοιων //containers// είναι | * **Sequence containers:** Αποθηκεύουν τα δεδομένα σειριακά, οδηγώντας σε χρόνους αναζήτησης γραμμικούς στο μέγεθος του πλήθους των στοιχείων που είναι αποθηκευμένα. Παραδείγματα τέτοιων //containers// είναι |
* **array:** Πίνακας σταθερού μεγέθους το οποίο προσδιορίζεται κατά τη δήλωση του πίνακα. | * **array:** Πίνακας σταθερού μεγέθους το οποίο προσδιορίζεται κατά τη δήλωση του πίνακα. |
* **vector:** Πίνακας μεταβλητού μεγέθους. Παρέχει δυνατότητα εισαγωγής στοιχείων σε οποιαδήποτε θέση του πίνακα. Η εισαγωγή/διαγραφή στο/από το τέλος του πίνακα είναι πράξη σταθερού κόστους, ενώ η εισαγωγή σε ή η διαγραφή από ενδιάμεση θέση συνεπάγεται την αντιγραφή των αποθηκευμένων στοιχείων που βρίσκονται μετά από τη συγκεκριμένη εγγραφή κατά μία θέση και είναι ανάλογη του μήκους αυτού. | * **vector:** Πίνακας μεταβλητού μεγέθους. Παρέχει δυνατότητα εισαγωγής στοιχείων σε οποιαδήποτε θέση του πίνακα. Η εισαγωγή/διαγραφή στο/από το τέλος του πίνακα είναι πράξη σταθερού κόστους, ενώ η εισαγωγή σε ή η διαγραφή από ενδιάμεση θέση συνεπάγεται την αντιγραφή των αποθηκευμένων στοιχείων που βρίσκονται μετά από τη συγκεκριμένη εγγραφή κατά μία θέση. Το κόστος είναι ανάλογο του μήκους αυτού. |
* **dequeue:** Πρόκειται για την γνωστή διπλοουρά που επιτρέπει την γρήγορη ένθεση και διαγραφή από την αρχή και το τέλος της ουράς. Για την εισαγωτή ή διαγραφή από ενδιάμεση θέση απαιτείται η αντιγραφή των στοιχείων που βρίσκονται πριν ή μετά τη συγκεκριμένη θέση κατά μία θέση και όπως και στην κλάση //vector// είναι ανάλογη του μήκους αυτού. | * **dequeue:** Πρόκειται για την γνωστή διπλοουρά που επιτρέπει την γρήγορη ένθεση και διαγραφή από την αρχή και το τέλος της ουράς. Για την εισαγωγή ή διαγραφή από ενδιάμεση θέση απαιτείται η αντιγραφή των στοιχείων που βρίσκονται πριν ή μετά τη συγκεκριμένη θέση κατά μία θέση. Όπως και στην κλάση //vector// το κόστος είναι ανάλογο του μήκους αυτού. |
* **list:** Πρόκειται για την διπλά συνδεδεμένη λίστα. Η λίστα δίνει την δυνατότητα διάτρεξης της δομής και προς τις δύο κατευθύνσεις, την εισαγωγή σε συγκεκριμένη θέση ή την διαγραφή στοιχείου από συγκεκριμένη θέση (δες σε αντιδιαστολή τη forward_list). Το κόστος αναζήτησης είναι ανάλογο των στοιχείων που είναι αποθηκευμένα στη λίστα, ενώ το κόστος εισαγωγής στοιχείου και διαγραφής στοιχείου είναι σταθερό. Η επιπλέον ευελιξία που παρέχεται σε σχέση με την forward list, έχει ως κόστος την διαχείριση ενός επιπλέον δείκτη σε κάθε κόμβο της λίστας σε σχέση με την απλά συνδεδεμένη λίστα. | * **list:** Πρόκειται για διπλά συνδεδεμένη λίστα. Η λίστα δίνει την δυνατότητα διάτρεξης της δομής και προς τις δύο κατευθύνσεις, την εισαγωγή σε συγκεκριμένη θέση ή την διαγραφή στοιχείου από συγκεκριμένη θέση (δείτε σε αντιδιαστολή τη forward_list). Το κόστος αναζήτησης είναι ανάλογο των στοιχείων που είναι αποθηκευμένα στη λίστα, ενώ το κόστος εισαγωγής στοιχείου και διαγραφής στοιχείου είναι σταθερό. Η επιπλέον ευελιξία που παρέχεται σε σχέση με την forward list, έχει ως κόστος την διαχείριση ενός επιπλέον δείκτη σε κάθε κόμβο της λίστας. |
* **forward_list:** Πρόκειται για την απλά συνδεδεμένη λίστα. Η λίστα δίνει την δυνατότητα διάτρεξης της δομής προς τη μία κατεύθυνση (από την αρχή προς το τέλος). Για την εισαγωγή και διαγραφή θα πρέπει οπωσδήποτε να γνωρίζουμε τον προηγούμενο κόμβο (θέση). Το κόστος αναζήτησης είναι ανάλογο των στοιχείων που είναι αποθηκευμένα στη λίστα, ενώ το κόστος εισαγωγής στοιχείου και διαγραφής στοιχείου είναι σταθερό. | * **forward_list:** Πρόκειται για απλά συνδεδεμένη λίστα. Η λίστα δίνει την δυνατότητα διάτρεξης της δομής προς τη μία κατεύθυνση (από την αρχή προς το τέλος). Για την εισαγωγή και διαγραφή θα πρέπει οπωσδήποτε να γνωρίζουμε τον προηγούμενο κόμβο (θέση). Το κόστος αναζήτησης είναι ανάλογο των στοιχείων που είναι αποθηκευμένα στη λίστα, ενώ το κόστος εισαγωγής στοιχείου και διαγραφής στοιχείου είναι σταθερό. |
* **Container Adapters:** Χρησιμοποιούν εσωτερικά ένα //sequence container// για να υλοποιήσουν την λειτουργικότητα τους. Οι βασικές κλάσεις είναι οι εξής: | * **Container Adapters:** Χρησιμοποιούν εσωτερικά ένα //sequence container// για να υλοποιήσουν την λειτουργικότητα τους. Οι βασικές κλάσεις είναι οι εξής: |
* **stack:** Υλοποιεί μία δομή Last-In-First-Out (LIFO) με την βοήθεια ενός //vector// ή //deque//. | * **stack:** Υλοποιεί μία δομή Last-In-First-Out (LIFO) με την βοήθεια ενός //vector// ή //deque//. |
* **queue:** Υλοποιεί μία δομή First-In-First-Out (FIFO) με την βοήθεια ενός //deque//. | * **queue:** Υλοποιεί μία δομή First-In-First-Out (FIFO) με την βοήθεια ενός //deque//. |
* **priority_queue:** Υλοποιεί μία ουρά προτεραιότητας. Προκειμένου να επιτευχθεί η προτεραιότητα κατά την εισαγωγή και διαγραφή στοιχείου εφαρμόζεται ο αλγόριθμος make_heap για την επίτευξη σωρού με λογαριθμικό κόστος στο μέγεθος των αποθηκευμένων στοιχείων της δομής. | * **priority_queue:** Υλοποιεί μία ουρά προτεραιότητας. Προκειμένου να επιτευχθεί η προτεραιότητα κατά την εισαγωγή και διαγραφή στοιχείου εφαρμόζεται ο αλγόριθμος make_heap για την επίτευξη σωρού με λογαριθμικό κόστος στο μέγεθος των αποθηκευμένων στοιχείων της δομής. |
* **Associative Containers:** Πρόκειται για δομές που τα στοιχεία εισάγονται ταξινομημένα σε αύξουσα σειρά. Η αποθήκευση γίνεται σε ένα ισοζυγισμένο δέντρο αναζητήσεως (π.χ.[[wp>Red–black_tree]]) και ο χρόνος αναζήτησης, εισαγωγής και διαγραφής είναι λογαριθμικός στο μέγεθος των αποθηκευμένων στοιχείων. Διακρίνονται σε [[cpp:stl:set|sets]] που είναι σύνολα από __μοναδικά__ στοιχεία-κλειδιά και [[cpp:stl:map|maps]] που είναι συνολά από απεικονίσεις __μοναδικών__ στοιχείων-κλειδιών σε τιμές. Παραλλαγές των παραπάνω κλάσεων είναι τα **multiset** και **multimap** όπου δίνεται η επιπλέον δυνατότητα αποθήκευσης περισσότερων του ενός ίδιων κλειδιών στην υφιστάμενη δομή. | * **Associative Containers:** Πρόκειται για δομές που τα στοιχεία εισάγονται ταξινομημένα σε αύξουσα σειρά. Η αποθήκευση γίνεται σε ένα ισοζυγισμένο δέντρο αναζητήσεως (π.χ.[[wp>Red–black_tree]]) και ο χρόνος αναζήτησης, εισαγωγής και διαγραφής είναι λογαριθμικός στο μέγεθος των αποθηκευμένων στοιχείων. Διακρίνονται σε [[cpp:stl:set|sets]] που είναι σύνολα από __μοναδικά__ στοιχεία-κλειδιά και [[cpp:stl:map|maps]] που είναι σύνολα από απεικονίσεις __μοναδικών__ στοιχείων-κλειδιών σε τιμές. Παραλλαγές των παραπάνω κλάσεων είναι τα **multiset** και **multimap** όπου δίνεται η επιπλέον δυνατότητα αποθήκευσης περισσότερων του ενός ίδιων κλειδιών στην υφιστάμενη δομή. |
* **Unordered Associative Containers:** Δομές ανάλογες με τους //Associative Containers// με την διαφορά ότι η αποθήκευση δεν γίνεται σε ισοζυγισμένο δέντρο αναζητήσεως, αλλά σε πίνακα κατακερματισμού ([[wp>Hash_table]]). Για τον λόγο αυτό, τα στοιχεία δεν αποθηκεύονται ταξινομημένα, αλλά με "τυχαία" σειρά. Η σειρά διάτρεξης τους αντιστοιχεί στη σειρά που τα κλειδιά είναι αποθηκευμένα στον πίνακα κατακερματισμού. Ο μέσος χρόνος αναζήτησης, εισαγωγής και διαγραφής είναι σταθερός στο μέγεθος των αποθηκευμένων στοιχείων, ενώ ο απαιτούμενος χώρος είναι περισσότερος (κατ' ελάχιστο διπλάσιος από τον αριθμό των αποθηκευμένων στοιχείων στην δομή). Οι κλάσεις **unordered_set** και **unordered_map** επιτρέπουν την αποθήκευση μοναδικών κλειδιών, ενώ οι δομές **unordered_multiset** και **unordered_multimap** επιτρέπουν την αποθήκευση περισσότερων του ενός ιδίων στοιχείων-κλειδιών στη δομή. | * **Unordered Associative Containers:** Δομές ανάλογες με τους //Associative Containers// με την διαφορά ότι η αποθήκευση δεν γίνεται σε ισοζυγισμένο δέντρο αναζητήσεως, αλλά σε πίνακα κατακερματισμού ([[wp>Hash_table]]). Για τον λόγο αυτό, τα στοιχεία δεν αποθηκεύονται ταξινομημένα, αλλά με "τυχαία" σειρά. Η σειρά διάτρεξης τους αντιστοιχεί στη σειρά που τα κλειδιά είναι αποθηκευμένα στον πίνακα κατακερματισμού. Ο μέσος χρόνος αναζήτησης, εισαγωγής και διαγραφής είναι σταθερός στο μέγεθος των αποθηκευμένων στοιχείων. Οι κλάσεις **unordered_set** και **unordered_map** επιτρέπουν την αποθήκευση μοναδικών κλειδιών, ενώ οι δομές **unordered_multiset** και **unordered_multimap** επιτρέπουν την αποθήκευση περισσότερων του ενός ιδίων στοιχείων-κλειδιών στη δομή. |
| |
| |
===== Κοινά χαρακτηριστικά για όλους τους containers ===== | ===== Κοινά χαρακτηριστικά για όλους τους Containers ===== |
| |
==== Αντιγραφή των στοιχείων προς ένθεση μέσα σε ένα Container ==== | ==== Εισαγωγή των στοιχείων μέσα σε ένα Container ==== |
| |
=== Χρήση Copy-Constructor ή άλλου κατασκευαστή === | Η εισαγωγή των στοιχείων γίνεται πάντοτε δημιουργώντας ένα αντίγραφο του αντικειμένου προς εισαγωγή μέσα στον //container//. Οι τρόποι με τους οποίους δημιουργείται το αντίγραφο περιγράφεται παρακάτω. |
| |
| === Χρήση Copy-Constructor ή κατάλληλου κατασκευαστή === |
| |
Κατά την ένθεση ενός στοιχείου σε ένα //container//, δημιουργείται πάντοτε ένα αντίγραφο του στοιχείου σε αυτόν. Για παράδειγμα, για την ένθεση στοιχείων της κλάσης [[https://courses.e-ce.uth.gr/ECE326/doku.php?do=export_code&id=cpp:templates&codeblock=0|Student]] μέσα σε ένα //container list// τα στοιχεία θα αντιγραφούν εντός του //list// στο τέλος της λίστας (οι μέθοδοι //insert_back// και //emplace_back// εισάγουν στο τέλος της λίστας) ως εξής: | Κατά την ένθεση ενός στοιχείου σε ένα //container//, δημιουργείται πάντοτε ένα αντίγραφο του στοιχείου σε αυτόν. Για παράδειγμα, για την ένθεση στοιχείων της κλάσης [[https://courses.e-ce.uth.gr/ECE326/doku.php?do=export_code&id=cpp:templates&codeblock=0|Student]] μέσα σε ένα //container list// τα στοιχεία θα αντιγραφούν εντός του //list// στο τέλος της λίστας (οι μέθοδοι //insert_back// και //emplace_back// εισάγουν στο τέλος της λίστας) ως εξής: |
</WRAP> | </WRAP> |
| |
Κατά την εισαγωγή ενός στοιχείου μέσω των συναρτήσεων //insert//, //insert_back//, //emplace//, //emplace_back// δημιουργείται πάντα ένα νέο αντικείμενο στον //container//. Η δημιουργία του αντικείμένου γίνεται είτε μέσω του copy-constructor (μέθοδοι //insert//, //insert_back//) ή μέσω εκείνου του κατασκευαστή που λαμβάνει ως παραμέτρους τους τύπους των ορισμάτων που περνιούνται στις μεθόδους //emplace// ή //emplace_back//. Στο παράδειγμα μας, τα αντικείμενα κατασκευάζονται με τη βοήθεια του κατασκευαστή ''Student(const char *name, int aem)''. | Κατά την εισαγωγή ενός στοιχείου μέσω των συναρτήσεων //insert//, //insert_back//, //emplace//, //emplace_back// δημιουργείται πάντα ένα νέο αντικείμενο στον //container// που αποτελεί αντίγραφο του προς εισαγωγή αντικειμένου. Η δημιουργία του αντικειμένου γίνεται είτε |
| * μέσω του copy-constructor, όταν καλούνται οι μέθοδοι //insert//, //insert_front// και //insert_back// ή |
| * μέσω εκείνου του κατασκευαστή που λαμβάνει ως παραμέτρους τους τύπους των ορισμάτων που περνιούνται στις μεθόδους //emplace// ή //emplace_front// ή //emplace_back//. Οι μέθοδοι τύπου //emplace// δημιουργούν ένα αντικείμενο χρησιμοποιώντας τον κατασκευαστή της κλάσης αντί για τη χρήση του //copy-constructor//. Το δυνητικό πλεονέκτημα των μεθόδων αυτών είναι ότι δεν κατασκευάζεται ένα αντικείμενο που στη συνέχεια αντιγράφεται, αλλά δημιουργείται μόνο ένα αντικείμενο εξ' αρχής. Στο προηγούμενο παράδειγμα, τα αντικείμενα κατασκευάζονται με τη βοήθεια του κατασκευαστή ''Student(const char *name, int aem)''. |
| |
=== Χρήση operator = === | === Χρήση του operator = === |
| |
Αντιστοίχως, στο παρακάτω πρόγραμμα ανατίθεται σε ένα //container// τύπου //array// περιεχόμενα μέσω του τελεστή %%[]%%. Μεταγλωττίζοντας και εκτελώντας το πρόγραμμα θα παρατηρήσετε ότι καλείται ο τελεστής %%=%% (//operator=//) της κλάσης //Student//. | Αντιστοίχως, στο παρακάτω πρόγραμμα ανατίθεται σε ένα //container// τύπου //array// περιεχόμενα μέσω του τελεστή %%[]%%. Μεταγλωττίζοντας και εκτελώντας το πρόγραμμα θα παρατηρήσετε ότι καλείται ο τελεστής %%=%% (//operator=//) της κλάσης //Student//. |
std::array<Student,2> myarray; | std::array<Student,2> myarray; |
for(int i=0; i<2; i++) { | for(int i=0; i<2; i++) { |
myarray[i] = students[i]; | myarray[i] = students[i]; // we use operator= here |
} | } |
| |
==== Προσδιορισμός εύρους στοιχείων ==== | ==== Προσδιορισμός εύρους στοιχείων ==== |
| |
Όταν στην STL προσδιορίζεται ένα εύρος στοιχείων εντός ενός //container// μεταξύ των υποτιθέμενων θέσεων //**start**// και //**stop**// ( οι θέσεις αυτές προσδιορίζονται πάντοτε από //iterators//), το διάστημα το οποιό υπολογίζεται είναι από //**start**// (συμπεριλαμβανομένου) έως και //**stop**// (μη συμπεριλαμβανομένου), ισοδύναμα: **[start, stop)**. Η παρακάτω εικόνα περιγράφει το διάστημα μεταξύ των θέσεων //start=1// και //stop//=6 ενός πίνακα. Το προσδιορισθέν διάστημα είναι από //start// έως και //stop-1//, δηλαδή από 1 έως και 5 (με πράσινο χρώμα). | Όταν στην STL προσδιορίζεται ένα εύρος στοιχείων εντός ενός //container// μεταξύ των υποτιθέμενων θέσεων //**start**// και //**stop**// ( οι θέσεις αυτές προσδιορίζονται πάντοτε από //iterators//), το διάστημα το οποίο υπολογίζεται είναι από //**start**// (συμπεριλαμβανομένου) έως και //**stop**// (μη συμπεριλαμβανομένου), ισοδύναμα: **[start, stop)**. Η παρακάτω εικόνα περιγράφει το διάστημα μεταξύ των θέσεων //start=1// και //stop//=6 ενός πίνακα. Το προσδιορισθέν διάστημα είναι από //start// έως και //stop-1//, δηλαδή από 1 έως και 5 (με πράσινο χρώμα). |
| |
{{ :cpp:stl:stl_range.png?400 |}} | {{ :cpp:stl:stl_range.png?400 |}} |