====== Κοινές συναρτήσεις για περισσότερους του ενός 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// ανάλογα με τον αριθμό των στοιχείων που θα εισάγει σε αυτόν.