Biblioteka STL

Język C++ wyposażono w specjalną bibliotekę STL (ang. Standard Template Library - biblioteka standardowych szablonów), która ułatwia programowanie z dynamicznymi strukturami danych. Z biblioteką STL spotykamy się już na samym początku pracy w C++ - strumienie cin i cout są obiektami tej biblioteki i udostępniają wygodny sposób komunikacji z konsolą znakową. Biblioteka STL definiuje tzw. klasy kontenerów, czyli obiektów, które mogą przechowywać dane dowolnego typu. Dzisiaj zapoznamy się z klasą szablonową vector oraz z jej funkcjami składowymi.

Klasa vector

W programowaniu często wykorzystujemy tablice dynamiczne do przechowywania danych, których ilości nie jesteśmy w stanie dokładnie przewidzieć w trakcie pisania programu. Tablice dynamiczne tworzyliśmy przy pomocy wskaźników oraz operatora new. Jednakże tak utworzona tablica posiadała bardzo ograniczone możliwości - wszelkie operacje na danych programista musiał definiować sam. W bibliotece STL jest klasa szablonowa vector, która pełni funkcję tablic dynamicznych. Aby w swoim programie uzyskać dostęp do tej klasy, musimy dołączyć plik nagłówkowy vector oraz określić przestrzeń nazw std:

 

...
#include <vector>
...
using namespace std;

Tablicę dynamiczną z wykorzystaniem klasy vector możemy utworzyć na kilka różnych sposobów (podsumowanie jest na końcu rozdziału). Najprostszym sposobem jest utworzenie pustej tablicy:

 

vector<typ_elementów> nazwa_tablicy;

 

Taka tablica będzie przechowywała dane o określonym typie elementów. Na początku tablica nie zawiera żadnego elementu. Możemy się o tym przekonać wywołując jej funkcję składową size(), która zwraca aktualnie przechowywaną przez tablicę liczbę elementów.

 

// Biblioteka STL
// Klasa szablonowa vector
//-------------------------
// Tworzenie pustej tablicy
//-------------------------
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//---------------------------

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  vector<int> T; // tworzymy pustą tablicę

  cout << T.size() << endl;

  return 0;
}
0

 

Wynikiem działania programu jest 0, tyle bowiem elementów przechowuje nasza tablica T.

Spytasz, po co komu pusta tablica? Teraz jest pusta, ale zaraz coś do niej wstawimy. Klasa vector posiada wiele funkcji składowych, które obsługują dane umieszczone w tablicy. Funkcja składowa push_back(v) dopisuje wartość v do końca danych, które przechowuje tablica. Poniższy program wprowadza do tablicy pięć liczb - wielokrotności 3:

 

// Biblioteka STL
// Klasa szablonowa vector
//-------------------------
// Dopisywanie na koniec tablicy
//-------------------------
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//---------------------------

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  vector<int> T; // tworzymy pustą tablicę
  unsigned i;

  for(i = 1; i <= 5; i++) T.push_back(3 * i);

  cout << T.size() << endl;

  return 0;
}
5

 

Teraz wynikiem działania programu jest liczba 5, ponieważ nasza tablica T przechowuje 5 wprowadzonych do niej liczb. Dostęp do danych może być uzyskany na kilka różnych sposobów:

 

T[indeks] - za pomocą indeksów, indeks musi być w zakresie od 0 do T.size() - 1

T.at(indeks) - za pomocą funkcji składowej at(). W tym przypadku sprawdzany jest zakres indeksów i, jeśli jest on niewłaściwy, funkcja generuje wyjatek.

T.front() - pierwszy element udostępnia funkcja składowa front().

T.back() - ostatni element udostępnia funkcja składowa back().

 

Poniższy program demonstruje zastosowanie tych funkcji:

 

// Biblioteka STL
// Klasa szablonowa vector
//-------------------------
// Dostęp do danych
//-------------------------
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//---------------------------

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  vector<int> T; // tworzymy pustą tablicę
  unsigned i;

  // wpisujemy 3 6 9 12 15

  for(i = 1; i <= 5; i++) T.push_back(3 * i);

  // wyświetlamy zawartość tablicy za pomocą indeksów:

  for(i = 0; i < T.size(); i++)
    cout << "T[" << i << "] = " << T[i] << endl;

  cout << endl;

  // wyświetlamy zawartość tablicy za pomocą funkcji at()

  for(i = 0; i < T.size(); i++)
    cout << "T.at(" << i << ") = " << T.at(i) << endl;

  cout << endl;

  // zmieniamy zawartość drugiego elementu za pomocą indeksu

  T[1] = 21;

  // zmieniamy zawartość trzeciego elementu za pomocą funkcji at()

  T.at(2) = 32;

  // zmieniamy zawartość pierwszego i ostatniego elementu

  T.front() = 123;
  T.back() = 456;

  // wyświetlamy pierwszy i ostatni element tablicy

  cout << "T.front() = " << T.front() << endl
       << "T.back()  = " << T.back() << endl << endl;

  // jeszcze raz wyświetlamy zmienioną tablicę

  for(i = 0; i < T.size(); i++)
    cout << "T[" << i << "] = " << T[i] << endl;

  cout << endl;

  return 0;
}
T[0] = 3
T[1] = 6
T[2] = 9
T[3] = 12
T[4] = 15

T.at(0) = 3
T.at(1) = 6
T.at(2) = 9
T.at(3) = 12
T.at(4) = 15

T.front() = 123
T.back() = 456

T[0] = 123
T[1] = 21
T[2] = 32
T[3] = 12
T[4] = 456

 

Zwróć uwagę, iż funkcje składowe at(), front() i back() zwracają odwołanie do elementu tablicy, zatem w programie zachowują się jak sam element - można np. użyć ich po lewej stronie operatora przypisania:

 

T.at(2) = 32;
T.front() = 123;
T.back() = 456;

 

Zamiast pustej tablicy możemy utworzyć tablicę zawierającą określoną liczbę elementów o zadanej wartości. W tym celu stosujemy zapis:

 

vector<typ_elementów> nazwa(liczba_elementów, wartość_elementów);

 

Poniższy program tworzy tablicę 10 elementową typu double i do każdego elementu wstawia liczbę pi = 3.1415926535

 

// Biblioteka STL
// Klasa szablonowa vector
//-------------------------
// Tablica o określonej zawartości
//-------------------------
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//---------------------------

#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;

int main()
{
  // tworzymy tablicę 10 elementową
  // elementy są typu double
  // każdy element początkowo zawiera 3.1415926535

  vector<double> X(10, 3.1415926535);
  unsigned i;

  cout << setprecision(10) << fixed;

  // pierwszy element podwajamy

  X.front() *= 2;

  // ostatni element potrajamy

  X.back() *= 3;

  for(i = 0; i < X.size(); i++)
    cout << "X[" << i << "] = " << X[i] << endl;

  return 0;
}
X[0] = 6.2831853070
X[1] = 3.1415926535
X[2] = 3.1415926535
X[3] = 3.1415926535
X[4] = 3.1415926535
X[5] = 3.1415926535
X[6] = 3.1415926535
X[7] = 3.1415926535
X[8] = 3.1415926535
X[9] = 9.4247779605

 

Jak to możliwe. Pamiętasz z poprzednich zajęć, gdy mówiliśmy, że klasa może posiadać kilka różnych konstruktorów? Konstruktory te muszą jedynie różnić się parametrami. Tak więć:

 

vector<typ> T;

 

wywołuje konstruktor bezparametrowy, który tworzy pustą tablicę.

 

vector<typ> T(n, v);

 

wywołuje inny konstruktor, który posiada dwa parametry n - liczbę elementów, v - wartość elementu. Ten konstruktor tworzy tablicę o pożądanej zawartości. To całe czary. Klasa vector posiada jeszcze dwa inne konstruktory, które umożliwiają utworzenie nowej tablicy na podstawie innej, którą wskażemy. Pierwszy z nich tworzy po prostu kopię innej tablicy. Składnia jest następująca:

 

vector<typ> nazwa(inna_tablica);

 

// Biblioteka STL
// Klasa szablonowa vector
//-------------------------
// Kopia tablicy
//-------------------------
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//---------------------------

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  // Tworzymy pierwszą tablicę

  vector<int> T1;

  // wypełniamy ją 10 liczbami parzystymi

  for(int i = 2; i <= 20; i += 2) T1.push_back(i);

  // tworzymy w T2 dokładną kopię tablicy T1

  vector<int> T2(T1);

  // wyświetlamy zawartość T2

  for(unsigned i = 0; i < T2.size(); i++)
    cout << "T2[" << i << "] = " << T2[i] << endl;

  cout << endl;

  return 0;
}
T2[0] = 2
T2[1] = 4
T2[2] = 6
T2[3] = 8
T2[4] = 10
T2[5] = 12
T2[6] = 14
T2[7] = 16
T2[8] = 18
T2[9] = 20

 

Ostatni sposób tworzenia tablicy opiera się na tzw. iteratorach. Iteratory w STL są wskaźnikami (zmiennymi przechowującymi adresy innych zmiennych), które mogą wskazywać kolejne elementy przechowywane w klasie. Zmienną iteratora dla klasy vector tworzymy następująco:

 

vector<typ>::iterator nazwa_iteratora;

 

Adres pierwszego elementu tablicy uzyskujemy za pomocą funkcji składowej begin(). Druga funkcja składowa end() daje adres poza ostatni element tablicy - czyli nie wskazujący już żadnego elementu, który przechowuje tablica:

 

obrazek

 

Adresy udostępniane przez funkcje składowe begin() i end() możemy wykorzystać w iteratorze:

 

iterator = T.begin();      // iterator wskazuje T[0]
iterator = T.begin() + 1;  // iterator wskazuje T[1]
iterator = T.begin() + 2;  // iterator wskazuje T[2]
...
iterator = T.end() - 1;    // iterator wskazuje ostatni element

 

Poniższy program demonstruje sposób wykorzystania iteratora do uzyskania dostępu do kolejnych elementów tablicy.

 

// Biblioteka STL
// Klasa szablonowa vector
//-------------------------
// Iterator
//-------------------------
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//---------------------------

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  // Tworzymy tablicę 10 elementów o wartości zero

  vector<int> T(10, 0);

  // tworzymy iterator

  vector<int>::iterator it;

  // tablicę wypełniamy kolejnymi setkami

  int v = 0;

  for(it = T.begin(); it != T.end(); it++) * it = (v += 100);

  // wyświetlamy zawartość tablicy

  for(it = T.begin(); it != T.end(); it++)
    cout << "* it = " << * it << endl;

  cout << endl;

  return 0;
}
* it = 100
* it = 200
* it = 300
* it = 400
* it = 500
* it = 600
* it = 700
* it = 800
* it = 900
* it = 1000

 

Czwarty sposób tworzenia tablicy vector pozwala utworzyć ją jako kopię fragmentu innej tablicy tego samego typu (tj. przechowującej elementy takiego samego typu). Do określenia wielkości tego fragmentu wykorzystujemy dwa iteratory it1, i it2:

 

vector<typ> nazwa(it1, it2);

 

Iterator it1 musi wskazywać na pierwszy element do skopiowania. Iterator it2 wskazuje poza ostatni element do skopiowania. Kopiowane elementy są od it1 do elementu poprzedzającego it2. Poniższy program demonstruje tę opcję:

 

// Biblioteka STL
// Klasa szablonowa vector
//-------------------------
// Kopiowanie fragmentu tablicy
//-------------------------
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//---------------------------

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  // Tworzymy tablicę bazową

  vector<int> T1;

  // wypełniamy ją liczbami od 0 do 9

  for(int i = 0; i < 10; i++) T1.push_back(i);

  // tworzymy dwa iteratory

  vector<int>::iterator it1, it2;

  // it1 ustawiamy na T1[3]

  it1 = T1.begin() + 3;

  // it2 ustawiamy na T1[7]

  it2 = T1.begin() + 7;

  // tworzymy T2 jako kopię od T1[3] do T1[6]

  vector<int> T2(it1,it2);

  // wyświetlamy obie tablice

  for(unsigned i = 0; i < T1.size(); i++)
  {
      cout << "T1[" << i << "] = " << T1[i];
      if(i < T2.size()) cout << " T2[" << i << "] = " << T2[i];
      cout << endl;
  }

  cout << endl;

  return 0;
}
T1[0] = 0 T2[0] = 3
T1[1] = 1 T2[1] = 4
T1[2] = 2 T2[2] = 5
T1[3] = 3 T2[3] = 6
T1[4] = 4
T1[5] = 5
T1[6] = 6
T1[7] = 7
T1[8] = 8
T1[9] = 9

 

Używając iteratorów musimy wiedzieć jedną ważną rzecz na temat klasy vector. Przechowywane elementy są umieszczone w pamięci jeden obok drugiego w spójnym bloku. Na początku klasa rezerwuje pewien określony obszar pamięci, który służy jej do składowania kolejnych elementów tablicy, w miarę jak są one do niej wstawiane. Ale w pewnym momencie może okazać się, że przydzielony początkowo obszar pamięci jest zbyt mały, aby pomieścić kolejne elementy. Co wtedy robi klasa vector? Rezerwuje w pamięci większy blok i przenosi do niego zawartość obecnej tablicy. Następnie likwiduje starą tablicę oddając zajętą przez nią pamięć do systemu. Powoduje to zmianę adresów elementów. Jeśli przygotowałeś sobie iterator, to przestaje on być ważny i nie można go używać już do wskazywania elementów tej tablicy.

 

Uwaga:

Po operacjach zmieniających rozmiar tablicy iteratory należy ponownie załadować, gdyż dane w tablicy mogą zmienić swój adres.

 

Ostatni element usuwamy z tablicy za pomocą funkcji składowej pop_back(). Rozmiar tablicy maleje o 1. Tracą ważność iteratory.

 

// Biblioteka STL
// Klasa szablonowa vector
//-------------------------
// Usuwanie ostatniego elementu
//-------------------------
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//---------------------------

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  // Tworzymy tablicę

  vector<int> T;

  // wypełniamy ją liczbami od 1 do 9

  for(int i = 1; i <= 9; i++) T.push_back(i);

  // wyświetlamy tablicę usunięciem

  for(unsigned i = 0; i < T.size(); i++)
      cout << "T[" << i << "] = " << T[i] << endl;

  cout << endl;

  // z końca tablicy usuwamy trzy elementy

  T.pop_back();
  T.pop_back();
  T.pop_back();

  // wyświetlamy tablicę po wstawieniu

  for(unsigned i = 0; i < T.size(); i++)
      cout << "T[" << i << "] = " << T[i] << endl;

  cout << endl;

  return 0;
}
T[0] = 1
T[1] = 2
T[2] = 3
T[3] = 4
T[4] = 5
T[5] = 6
T[6] = 7
T[7] = 8
T[8] = 9

T[0] = 1
T[1] = 2
T[2] = 3
T[3] = 4
T[4] = 5
T[5] = 6

 

Do usuwania dowolnego elementu z tablicy stosujemy funkcję erase() w sposób następujący:

 

tablica.erase(iterator);

 

Iterator wskazuje element do usunięcia. Po tej operacji tablica zawiera o jeden element mniej. Elementy leżące ponad pozycją iteratora zostają przesunięte w kierunku początku tablicy. Iteratory tracą ważność.

 

// Biblioteka STL
// Klasa szablonowa vector
//-------------------------
// Usuwanie elementu
//-------------------------
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//---------------------------

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  // Tworzymy tablicę

  vector<int> T;

  // wypełniamy ją liczbami od 1 do 9

  for(int i = 1; i <= 9; i++) T.push_back(i);

  // tworzymy iterator, ustawiając go na T[3]

  vector<int>::iterator it = T.begin() + 3;

  // wyświetlamy tablicę przed usunięciem

  for(unsigned i = 0; i < T.size(); i++)
      cout << "T[" << i << "] = " << T[i] << endl;

  cout << endl;

  // usuwamy T[3] z tablicy

  T.erase(it);

  // wyświetlamy tablicę po usunięciu

  for(unsigned i = 0; i < T.size(); i++)
      cout << "T[" << i << "] = " << T[i] << endl;

  cout << endl;

  return 0;
}
T[0] = 1
T[1] = 2
T[2] = 3
T[3] = 4
T[4] = 5
T[5] = 6
T[6] = 7
T[7] = 8
T[8] = 9

T[0] = 1
T[1] = 2
T[2] = 3
T[3] = 5
T[4] = 6
T[5] = 7
T[6] = 8
T[7] = 9

 

Z tablicy możemy również usunąć ciąg elementów, posługując się dwoma iteratorami:

 

tablica.erase(it1, it2);

 

it1 - wskazuje pierwszy element do usunięcia
it2 - wskazuje poza ostatni element do usunięcia

 

Rozmiar tablicy maleje o liczbę usuniętych z niej elementów. Tracą ważność iteratory.

 

// Biblioteka STL
// Klasa szablonowa vector
//-------------------------
// Usuwanie kilku przyległych elementów
//-------------------------
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//---------------------------

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  // Tworzymy tablicę

  vector<int> T;

  // wypełniamy ją liczbami od 1 do 9

  for(int i = 1; i <= 9; i++) T.push_back(i);

  // wyświetlamy tablicę przed usunięciem

  for(unsigned i = 0; i < T.size(); i++)
      cout << "T[" << i << "] = " << T[i] << endl;

  cout << endl;

  // tworzymy dwa iteratory, ustawiając je na T[3] i T[7]

  vector<int>::iterator it1 = T.begin() + 3;
  vector<int>::iterator it2 = T.begin() + 7;

  // usuwamy T[3]...T[6] z tablicy

  T.erase(it1,it2);

  // wyświetlamy tablicę po usunięciu

  for(unsigned i = 0; i < T.size(); i++)
      cout << "T[" << i << "] = " << T[i] << endl;

  cout << endl;

  return 0;
}
T[0] = 1
T[1] = 2
T[2] = 3
T[3] = 4
T[4] = 5
T[5] = 6
T[6] = 7
T[7] = 8
T[8] = 9

T[0] = 1
T[1] = 2
T[2] = 3
T[3] = 8
T[4] = 9

 

Do tablicy możemy wstawiać elementy na trzy różne sposoby za pomocą funkcji składowej insert():

 

tablica.insert(iterator, wartość);

 

Na pozycji wskazywanej przez iterator tablica zostaje rozsunięta i w powstałe miejsce jest wstawiana podana wartość. Rozmiar tablicy rośnie o 1. Tracą ważność iteratory.

 

// Biblioteka STL
// Klasa szablonowa vector
//-------------------------
// Wstawianie elementu
//-------------------------
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//---------------------------

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  // Tworzymy tablicę

  vector<int> T;

  // wypełniamy ją liczbami od 1 do 9

  for(int i = 1; i <= 9; i++) T.push_back(i);

  // wyświetlamy tablicę przed wstawieniem

  for(unsigned i = 0; i < T.size(); i++)
      cout << "T[" << i << "] = " << T[i] << endl;

  cout << endl;

  // tworzymy iterator, ustawiając go na T[3]

  vector<int>::iterator it = T.begin() + 3;

  // na pozycji T[3] wstawiamy liczbę 1234

  T.insert(it, 1234);

  // wyświetlamy tablicę po wstawieniu

  for(unsigned i = 0; i < T.size(); i++)
      cout << "T[" << i << "] = " << T[i] << endl;

  cout << endl;

  return 0;
}
T[0] = 1
T[1] = 2
T[2] = 3
T[3] = 4
T[4] = 5
T[5] = 6
T[6] = 7
T[7] = 8
T[8] = 9

T[0] = 1
T[1] = 2
T[2] = 3
T[3] = 1234
T[4] = 4
T[5] = 5
T[6] = 6
T[7] = 7
T[8] = 8
T[9] = 9

 

tablica.insert(iterator, liczba_komórek, wartość);

 

Na pozycji wskazywanej przez iterator zostanie wstawiona podana liczba komórek o zadanej wartości. Rozmiar tablicy rośnie o liczbę wstawionych komórek. Tracą ważność iteratory.

 

// Biblioteka STL
// Klasa szablonowa vector
//-------------------------
// Wstawianie kilku elementów
//-------------------------
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//---------------------------

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  // Tworzymy tablicę

  vector<int> T;

  // wypełniamy ją liczbami od 1 do 9

  for(int i = 1; i <= 9; i++) T.push_back(i);

  // wyświetlamy tablicę przed wstawieniem

  for(unsigned i = 0; i < T.size(); i++)
      cout << "T[" << i << "] = " << T[i] << endl;

  cout << endl;

  // tworzymy iterator, ustawiając go na T[3]

  vector<int>::iterator it = T.begin() + 3;

  // na pozycji T[3] wstawiamy 5 razy liczbę 1234

  T.insert(it, 5, 1234);

  // wyświetlamy tablicę po wstawieniu

  for(unsigned i = 0; i < T.size(); i++)
      cout << "T[" << i << "] = " << T[i] << endl;

  cout << endl;

  return 0;
}
T[0] = 1
T[1] = 2
T[2] = 3
T[3] = 4
T[4] = 5
T[5] = 6
T[6] = 7
T[7] = 8
T[8] = 9

T[0] = 1
T[1] = 2
T[2] = 3
T[3] = 1234
T[4] = 1234
T[5] = 1234
T[6] = 1234
T[7] = 1234
T[8] = 4
T[9] = 5
T[10] = 6
T[11] = 7
T[12] = 8
T[13] = 9

 

Istnieje również możliwość wstawienia fragmentu innej tablicy. W tym przypadku używamy trzech iteratorów:

 

tablica.insert(it1, it2, it3);

 

it1 - wskazuje pozycję wstawiania w tablicy.

it2 - wskazuje początkowy element w innej tablicy

it3 - wskazuje poza ostatni do kopiowania element w innej tablicy

Kopiowane będą elementy od it2 do elementu poprzedzającego it3.

 

// Biblioteka STL
// Klasa szablonowa vector
//-------------------------
// Kopiowanie fragmentu innej tablicy
//-------------------------
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//---------------------------

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  // Tworzymy tablicę nr 1

  vector<int> T1;

  // wypełniamy ją liczbami od 1 do 9

  for(int i = 1; i <= 9; i++) T1.push_back(i);

  // Tworzymy tablicę nr 2

  vector<int> T2;

  // wypełniamy ją setkami od 100 do 900

  for(int i = 100; i <= 900; i += 100) T2.push_back(i);

  // tworzymy trzy iteratory

  vector<int>::iterator it1, it2, it3;

  // it1 ustawiamy na T1[3]

  it1 = T1.begin() + 3;

  // it2 ustawiamy na T2[4]

  it2 = T2.begin() + 4;

  // it3 ustawiamy na T2[7]

  it3 = T2.begin() + 7;

  // W T1 na pozycji 3 wstawiamy T2[4]...T2[6]

  T1.insert(it1, it2, it3);

  // wyświetlamy T1

  for(unsigned i = 0; i < T1.size(); i++)
    cout << "T1[" << i << "] = " << T1[i] << endl;

  cout << endl;

  // wyświetlamy T2

  for(unsigned i = 0; i < T2.size(); i++)
    cout << "T2[" << i << "] = " << T2[i] << endl;

  cout << endl;

  return 0;
}
T1[0] = 1
T1[1] = 2
T1[2] = 3
T1[3] = 500
T1[4] = 600
T1[5] = 700
T1[6] = 4
T1[7] = 5
T1[8] = 6
T1[9] = 7
T1[10] = 8
T1[11] = 9

T2[0] = 100
T2[1] = 200
T2[2] = 300
T2[3] = 400
T2[4] = 500
T2[5] = 600
T2[6] = 700
T2[7] = 800
T2[8] = 900

 

Ostatnią na dzisiaj operacją jest wymiana zawartości dwóch tablic. Realizuje to funkcja składowa swap():

 

tablica1.swap(tablica2);

 

Po tej operacji w tablicy1 będziemy mieli zawartość tablicy2, a w tablicy2 będzie to, co wcześniej było w tablicy1. Ciekawostką jest fakt, iż dane wcale nie są wymieniane w pamięci - klasy wymieniają się jedynie adresami tablic. Dzięki temu czas operacji jest stały i nie zależy od liczby przechowywanych w tablicach elementów.

 

// Biblioteka STL
// Klasa szablonowa vector
//-------------------------
// Wymiana zawartości tablic
//-------------------------
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//---------------------------

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  // Tworzymy tablicę nr 1

  vector<int> T1;

  // wypełniamy ją liczbami od 1 do 5

  for(int i = 1; i <= 5; i++) T1.push_back(i);

  // Tworzymy tablicę nr 2

  vector<int> T2;

  // wypełniamy ją setkami od 400 do 900

  for(int i = 400; i <= 900; i += 100) T2.push_back(i);

  // wymieniamy zawartości obu tablic

  T1.swap(T2);

  // wyświetlamy T1

  for(unsigned i = 0; i < T1.size(); i++)
    cout << "T1[" << i << "] = " << T1[i] << endl;

  cout << endl;

  // wyświetlamy T2

  for(unsigned i = 0; i < T2.size(); i++)
    cout << "T2[" << i << "] = " << T2[i] << endl;

  cout << endl;

  return 0;
}
T1[0] = 400
T1[1] = 500
T1[2] = 600
T1[3] = 700
T1[4] = 800
T1[5] = 900

T2[0] = 1
T2[1] = 2
T2[2] = 3
T2[3] = 4
T2[4] = 5

 

Podsumowanie

Poniżej podsumowujemy opisane funkcje oraz kilka innych, które mogą być użyteczne w trakcie pracy z klasą vector. Najlepiej wydrukuj tabelkę i noś ją przy sobie.

 

Tworzenie tablicy
vector <typ> tablica; pusta tablica
vector <typ> tablica(n , v); tablica o n elementach, każdy o wartości v
vector <typ> tablica(inna_tablica); kopia innej tablicy o takiej samej zawartości
vector <typ> tablica(it1, it2); kopia fragmentu innej tablicy.
it1 - iterator wskazujący pierwszy element do skopiowania
it2 - iterator wskazujący poza ostatni element do skopiowania
Tworzenie zmiennej typu iterator
vector <typ> :: iterator nazwa;  
Dostęp do elementów tablicy
tablica[indeks] poprzez indeksowanie - nie sprawdza zakresów indeksów
tablica.at(indeks) poprzez funkcję składową, która sprawdza zakresy indeksów. Jeśli indeks wykracza poza rozmiar tablicy, generowany jest wyjątek.
tablica.front() odwołanie do pierwszego elementu
tablica.back() odwołanie do ostatniego elementu
Rozmiar tablicy
tablica.size() zwraca liczbę elementów przechowywanych w tablicy
tablica.empty() jeśli tablica nie przechowuje żadnego elementu, zwraca true. Inaczej zwraca false.
tablica.max_size() zwraca maksymalny rozmiar tablicy - czyli liczbę elementów, którą tablica może przechować
Funkcje związane z iteratorami
tablica.begin() zwraca iterator do pierwszego elementu tablicy
tablica.end() zwraca iterator poza ostatni element w tablicy. Iterator ten nie wskazuje żadnego elementu w tablicy.
Wstawianie danych do tablicy
tablica.push_back(v) dopisuje wartość v na końcu tablicy. Rozmiar tablicy rośnie o 1. Iteratory tracą ważność.
tablica.insert(it,v) wstawia na pozycję iteratora it wartość v. Rozmiar tablicy rośnie o 1. Iteratory tracą ważność.
tablica.insert(it, n, v) wstawia od pozycji iteratora it n wartości v. Rozmiar tablicy rośnie o n. Iteratory tracą ważność.
tablica.insert(it1, it2, it3) wstawia na pozycji iteratora it1 fragment innej tablicy, zdefiniowany przez iteratory it2 i it3:
it2 - wskazuje pierwszy element do wstawienia
it3 - wskazuje poza ostatni element do wstawienia
Rozmiar tablicy rośnie o liczbę wstawionych elementów. Iteratory tracą ważność.
Usuwanie danych z tablicy
tablica.clear() usuwa z tablicy wszystkie elementy. Po tej operacji rozmiar tablicy wynosi 0. Iteratory tracą ważność.
tablica.pop_back() usuwa z tablicy ostatni element. Rozmiar tablicy zmniejsza się o 1. Iteratory tracą ważność.
tablica.erase(it) usuwa element wskazywany przez iterator it. Rozmiar tablicy zmniejsza się o 1. Iteratory tracą ważność.
tablica.erase(it1, it2) usuwa ciąg przyległych elementów.
it1 - wskazuje pierwszy element do usunięcia w tym ciągu.
it2 - wskazuje poza ostatni element do usunięcia.
Rozmiar tablicy zmniejsza się o liczbę usuniętych elementów. Iteratory tracą ważność.
Wymiana zawartości tablic
tablica1.swap(tablica2) wymienia zawartość tablicy1 z tablicą2. Iteratory pozostają ważne.
Pozostałe funkcje składowe
tablica.resize(n) zmienia rozmiar tablicy na n komórek. Jeśli tablica posiadała wcześniej większy rozmiar, to elementy ponad n są usuwane. Jeśli rozmiar był  mniejszy, to na końcu tablicy zostają wstawione puste elementy do osiągnięcia rozmiaru n. Iteratory tracą ważność.
tablica.resize(n,v) działa jak powyżej, dodatkowe elementy są inicjowane na wartość v.
tablica.reserve(n) rezerwuje dla tablicy obszar do przechowywania przynajmniej n elementów. Funkcja ta zapewnia, iż tablica nie będzie zmieniać swojego położenia w pamięci, jeśli jej rozmiar nie przekroczy n. Najlepiej wywołać ją przed zapisem elementów do tablicy.
tablica.assign(n,v) pozwala przypisać tablicy nową zawartość. Stara zawartość jest usuwana, a na jej miejsce powstaje n komórek o wartości v.
tablica.assign(it1, it2) usuwa bieżącą zawartość tablicy i na jej miejsce kopiuje fragment innej tablicy zdefiniowany przez iteratory:
it1 - wskazuje pierwszy element do skopiowania
it2 - wskazuje poza ostatni element do skopiowania

 


   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2024 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe