User Tools

Site Tools


cpp:stl:container_common_functions

Κοινές συναρτήσεις για περισσότερους του ενός containers

Εισαγωγή στοιχείου

Με εξαίρεση την κλάση 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.

student_list_insert.cpp
#include <iostream>     // std::cout
#include <algorithm>    // std::copy
#include <list>         // 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<Student> 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<Student>::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.

student_set_insert.cpp
#include <iostream>     // std::cout
#include <algorithm>    // std::copy
#include <set>         // 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<Student> 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<Student>::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://cplusplus.com/list/erase

list_erase.cpp
#include <iostream>
#include <list>
 
int main () {
  std::list<int> mylist;
  std::list<int>::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://cplusplus.com/set/erase

set_erase.cpp
// erasing from set
#include <iostream>
#include <set>
 
int main ()
{
  std::set<int> myset;
  std::set<int>::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 γίνεται μέσω της συνάρτησης std::find. Όπως θα δείτε και από τον ενδεικτικό κώδικα στο link η συνάρτηση λειτουργεί διατρέχοντας τον container με την βοήθεια ενός iterator. Το κόστος αναζήτησης είναι γραμμικό στο πλήθος των στοιχείων του container και για αυτό δεν αποτελεί βέλτιστη επιλογή για associative και unordered associative containers. Δείτε το παρακάτω ενδεικτικό παράδειγμα αναζήτησης σε μία λίστα. Η συνάρτηση std::find επιστρέφει έναν iterator που δείχνει στην πρώτη θέση που εμφανίζεται το στοιχείο που αναζητούμε (μπορεί να εμφανίζεται σε περισσότερες θέσεις). Εάν δεν υπάρχει το στοιχείο που αναζητούμε η συνάρτηση find επιστρέφει έναν iterator που δείχνει στο σημείο του container που δείχνει και η συνάρτηση end. Το παρακάτω παράδειγμα είναι ενδεικτικό της χρήσης της find.

find_in_vector.cpp
//find example
#include <iostream>     // std::cout
#include <algorithm>    // std::find
#include <vector>       // 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<int> 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

find_in_set.cpp
#include <iostream>
#include <set>
 
int main ()
{
  std::set<int> myset;
  std::set<int>::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

find_in_unordered_set.cpp
// unordered_set::find
#include <iostream>
#include <string>
#include <unordered_set>
 
template<typename T>
void print_set(std::unordered_set<T>& 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<std::string> myset;
  std::unordered_set<std::string>::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. Παρακάτω δίνεται ένα παράδειγμα όπου αντιγράφονται τα περιεχόμενα ενός std::array αντιγράφονται σε ένα std::vector με εξαίρεση το πρώτο και το τελευταίο στοιχείο του array.

vector_assign.cpp
#include <iostream>
#include <vector>
#include <array>
#include <iomanip>
using namespace std;
 
template<typename T>
void print(vector<T> v) {
  for(auto it = v.cbegin(); it!=v.cend(); it++) 
    cout << setw(3) << *it;
  cout << endl;
}
 
int main () {
  vector<int> v = {1,2,3};
  array<int,6> 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 ανάλογα με τον αριθμό των στοιχείων που θα εισάγει σε αυτόν.

cpp/stl/container_common_functions.txt · Last modified: 2023/05/30 19:18 by gthanos