====== Κοινές συναρτήσεις για περισσότερους του ενός containers ====== ===== Εισαγωγή στοιχείου ===== Με εξαίρεση την κλάση [[array|std::array]] που το μέγεθος των πινάκων που δημιουργεί είναι σταθερό και δηλώνεται κατά τη δήλωση του πίνακα, οι υπόλοιποι //containers// μπορούν να μεταβάλλουν το αριθμό των στοιχείων που αποθηκεύουν. Για την εισαγωγή ενός στοιχείου σε έναν //container// υπάρχουν οι συναρτήσεις //insert// για την εισαγωγή ενός αντιγράφου του στοιχείου στον container και //emplace// για την δημιουργία ενός αντικειμένου και εισαγωγή του στον //container//. Επιπλέον, μόνο για τους //sequence containers// η //insert// λαμβάνει ως πρώτο όρισμα έναν //iterator// που δηλώνει τη θέση εισαγωγής του στοιχείου στον container. Για τις υπόλοιπες κατηγορίες //containers//, η //insert// δε λαμβάνει ως πρώτο όρισμα έναν //iterator// (υπάρχουν περιπτώσεις που λαμβάνει, αλλά αυτό είναι ενδεικτικό και συνιστάται να αποφεύγετε τη χρήση του). Παραδείγματα: ==== A. Ένθεση στους sequence_containers list, forward_list, vector και dequeue ==== Σε ένα //sequence container// είναι υποχρεωτικό να προσδιορίσουμε τη θέση εισαγωγής του στοιχείου μέσω ενός //iterator// που παρέχεται ως πρώτο όρισμα στη συνάρτηση //insert//. #include // std::cout #include // std::copy #include // std::list #include "Student.hpp" int main () { Student students[] = { Student("Peter_Pan", 1234), Student("Tinker_Bell", 1235) }; std::cerr << "----- Init list -----" << std::endl; std::list mylist; for(int i=0; i<2; i++) { mylist.insert(mylist.begin(),students[i]); // copy-constructor, insert first mylist.insert(mylist.end(),students[i]); // copy-constructor, insert last } mylist.emplace(mylist.end(), "Mickey_Mouse", 1237); // argument construct, insert last std::cerr << "-------------------------\n"; std::cerr << "mylist contains:"; for (std::list::iterator it = mylist.begin(); it!=mylist.end(); ++it) std::cerr << ' ' << *it; std::cerr << std::endl; std::cerr << "-------------------------\n"; return 0; } Η διαφορά ανάμεσα στις μεθόδους //insert// και //emplace// είναι η εξής: * Στη μέθοδο //insert// παρέχουμε ένα αντικείμενο και η μέθοδος κατασκευάζει ένα αντίγραφο του μέσω του κατασκευαστή αντιγραφέα (copy-constructor) της κλάσης //Student//. * Στη μέθοδο //empace// παρέχουμε τα ορίσματα μέσω των οποίων κατασκευάζεται ένα αντικείμενο τύπου Student, μέσω του κατασκευαστή ''Student(const char *name, int aem);''. ==== Β. Ένθεση σε set, unordered set ==== Σε ένα //associative container// δεν μπορούμε να προσδιορίσουμε τη θέση εισαγωγής του στοιχείου σε αυτόν. Ως εκ τούτου η //insert// δεν λαμβάνει ως πρώτο όρισμα έναν //iterator//. #include // std::cout #include // std::copy #include // std::set #include "Student.hpp" int main () { Student students[] = { Student("Peter_Pan", 1234), Student("Tinker_Bell", 1235) }; std::cerr << "----- Init set -----" << std::endl; std::set myset; for(int i=0; i<2; i++) { myset.insert(students[i]); // copy-constructor, insert first myset.insert(students[i]); // copy-constructor, insert last } myset.emplace("Mickey_Mouse", 1237); // argument construct, insert last std::cerr << "-------------------------\n"; std::cerr << "myset contains:"; for (std::set::iterator it = myset.begin(); it!=myset.end(); ++it) std::cerr << ' ' << *it; std::cerr << std::endl; std::cerr << "-------------------------\n"; return 0; } ===== Διαγραφή στοιχείου ===== Η διαγραφή στοιχείου είναι ανάλογη της εισαγωγής και γίνεται μέσω της συνάρτησης //erase//. H συνάρτηση επιστρέφει έναν //iterator// στο επόμενο στοιχείο από αυτό που έχει διεγραφεί. Για τους //sequence containers// σε αναλογία με την διαδικασία εισαγωγής, η συνάρτηση λαμβάνει ως όρισμα έναν //iterator// που δηλώνει τη θέση διαγραφής από τον container. Για τους //associative containers// η διαγραφή γίνεται παρέχοντας ως όρισμα τη θέση του κλειδιού (μέσω //iterator//) ή την τιμή του κλειδιού που επιθυμούμε να διαγράψουμε. ==== A. Διαγραφή από λίστα ==== Το παρακάτω παράδειγμα είναι από τη σελίδα [[http://www.cplusplus.com/reference/list/list/erase/|http://cplusplus.com/list/erase]] #include #include int main () { std::list mylist; std::list::iterator it1, it2; // insert values: for (int i=1; i<10; ++i) mylist.push_back(i*10); // 10 20 30 40 50 60 70 80 90 it1 = it2 = mylist.begin(); // ^^ advance (it2,6); // ^ ^ ++it1; // ^ ^ it1 = mylist.erase (it1); // 10 30 40 50 60 70 80 90 // ^ ^ it2 = mylist.erase (it2); // 10 30 40 50 60 80 90 // ^ ^ // 10 30 40 50 60 80 90 ++it1; // ^ ^ --it2; // ^ ^ it1=mylist.erase (it1,it2); // 10 30 60 80 90 // ^ std::cout << "mylist contains:"; for (it1=mylist.begin(); it1!=mylist.end(); ++it1) std::cout << ' ' << *it1; std::cout << '\n'; return 0; } ==== B. Διαγραφή από set ==== Το παρακάτω παράδειγμα είναι από τη σελίδα [[http://www.cplusplus.com/reference/set/erase/|http://cplusplus.com/set/erase]] // erasing from set #include #include int main () { std::set myset; std::set::iterator it; // insert some values: for (int i=1; i<10; i++) myset.insert(i*10); // 10 20 30 40 50 60 70 80 90 it = myset.begin(); // 10 20 30 40 50 60 70 80 90 // ^ ++it; // 10 20 30 40 50 60 70 80 90 // ^ myset.erase (it); // 10 30 40 50 60 70 80 90 myset.erase (40); // 10 30 50 60 70 80 90 it = myset.find (60); // 10 30 50 60 70 80 90 // ^ myset.erase (it, myset.end()); // 10 30 50 std::cout << "myset contains:"; for (it=myset.begin(); it!=myset.end(); ++it) std::cout << ' ' << *it; std::cout << '\n'; return 0; } ===== Αναζήτηση στοιχείου ===== Η διαδικασία αναζήτησης ενός στοιχείου είναι διαφορετική εάν αναζητούμε σε //sequence container// ή σε //associative container//. ==== Αναζήτηση σε sequence container ==== H αναζήτηση σε sequence container γίνεται μέσω της συνάρτησης [[http://www.cplusplus.com/reference/algorithm/find/|std::find]]. Όπως θα δείτε και από τον ενδεικτικό κώδικα στο link η συνάρτηση λειτουργεί διατρέχοντας τον //container// με την βοήθεια ενός //iterator//. Το κόστος αναζήτησης είναι γραμμικό στο πλήθος των στοιχείων του //container// και για αυτό δεν αποτελεί βέλτιστη επιλογή για //associative// και //unordered associative containers//. Δείτε το παρακάτω ενδεικτικό παράδειγμα αναζήτησης σε μία λίστα. Η συνάρτηση [[http://www.cplusplus.com/reference/algorithm/find/|std::find]] επιστρέφει έναν //iterator// που δείχνει στην πρώτη θέση που εμφανίζεται το στοιχείο που αναζητούμε (μπορεί να εμφανίζεται σε περισσότερες θέσεις). Εάν δεν υπάρχει το στοιχείο που αναζητούμε η συνάρτηση //find// επιστρέφει έναν //iterator// που δείχνει στο σημείο του //container// που δείχνει και η συνάρτηση //end//. Το παρακάτω παράδειγμα είναι ενδεικτικό της χρήσης της //find//. //find example #include // std::cout #include // std::find #include // std::vector int main () { // using std::find with array and pointer: int myints[] = { 10, 40, 30, 30, 40, 50, 30, 60, 30 }; int *p; int search_int; std::cout << "Enter an integer to search for: "; std::cin >> search_int; p = std::find (myints, myints+9, search_int); if (p != myints+9) std::cout << "First occurance of " << search_int << " in myints: " << *p << '\n'; else std::cout << search_int << " not found in myints: " << '\n'; std::vector myvector (myints,myints+9); auto it = myvector.begin(); bool found = false; while(true) { it = find (it , myvector.end(), search_int); if (it != myvector.end()) { std::cout << search_int << " found in myvector at pos: " << it - myvector.begin() << '\n'; it++; found = true; } else { if(!found) std::cout << search_int <<" not found in myvector\n"; break; } } return 0; } ==== Αναζήτηση σε associative container και unordered associative container ==== Επειδή η συνάρτηση //find// ψάχνει γραμμικά μέσα στο περιεχόμενο του container δεν είναι βέλτιστή για containers που περιγράφονται από δέντρα ή από πίνακα κατακερματισμού. Αυτοί οι //containers// διαθέτουν δικές τους εξειδικευμένες συναρτήσεις //find// που ταιριάζουν στα χαρακτηριστικά της περιεχόμενης δομής που χρησιμοποιούν. === Α. Αναζήτηση σε set === #include #include int main () { std::set myset; std::set::iterator it; // set some initial values: for (int i=1; i<=5; i++) myset.insert(i*10); // set: 10 20 30 40 50 it=myset.find(20); myset.erase (it); myset.erase (myset.find(40)); std::cout << "myset contains:"; for (it=myset.begin(); it!=myset.end(); ++it) std::cout << ' ' << *it; std::cout << '\n'; return 0; } === Β. Αναζήτηση σε unordered set === // unordered_set::find #include #include #include template void print_set(std::unordered_set& myset) { std::cout << "myset contains:"; for (auto it=myset.begin(); it!=myset.end(); ++it) std::cout << ' ' << *it; std::cout << '\n'; } int main () { std::unordered_set myset; std::unordered_set::iterator it; std::string word[] = { "sugar", "choco", "milk", "banana", "coffee" }; // unordered_set some initial values: for (int i=0; i<5; i++) myset.emplace(word[i]); print_set(myset); it=myset.find(std::string("biscuits")); if(it != myset.end()) { myset.erase (it); std::cout << "'biscuits' erased\n"; } else std::cout << "'biscuits' not found\n"; print_set(myset); myset.erase (myset.find(std::string("milk"))); std::cout << "'milk' erased\n"; print_set(myset); return 0; } Όλες οι παραλλαγές της συνάρτησης //find// επιστρέφουν έναν //iterator// που δείχνει στην πρώτη (ή στη μοναδική) εμφάνιση του στοιχείου που ψάχνουμε στον //container//. Σε περίπτωση που δεν βρεθεί το στοιχείο ο //iterator// δείχνει μετά το τέλος του //container// εκεί που δείχνει και ο //iterator// που επιστρέφεται από τη συνάρτηση //end//. ===== Ανάθεση των περιεχομένων ενός container από τα περιεχόμενα ενός άλλου container ===== Η ανάθεση των περιεχομένων ενός //container// από τα περιεχόμενα ενός άλλου //container// (δεν έχει σημασία ο τύπος) γίνεται μέσω της συνάρτησης //assign//. Παρακάτω δίνεται ένα παράδειγμα όπου αντιγράφονται τα περιεχόμενα ενός [[cpp:stl:array|std::array]] αντιγράφονται σε ένα [[cpp:stl:vector|std::vector]] με εξαίρεση το πρώτο και το τελευταίο στοιχείο του //array//. #include #include #include #include using namespace std; template void print(vector v) { for(auto it = v.cbegin(); it!=v.cend(); it++) cout << setw(3) << *it; cout << endl; } int main () { vector v = {1,2,3}; array a = {10, 20, 30, 40, 50, 60}; /* Assigns 20, 30, 40, 50 */ v.assign(a.begin()+1, a.end()-1); // 10 20 30 40 50 60 // ^ ^ // begin()+1 end()-1 print(v); } H συνάρτηση //assign// διαγράφει τα υφιστάμενα περιεχόμενα του //container// πριν ανάθεση των νέων περιεχομένων. Επιπλέον, προσαρμόζει το μέγεθος του //container// ανάλογα με τον αριθμό των στοιχείων που θα εισάγει σε αυτόν.