![]() |
Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych. Autor artykułu: mgr Jerzy Wałaszek, wersja1.0 |
©2009 mgr
Jerzy Wałaszek
|
Praktycznie każda współczesna dystrybucja języka C++ zawiera moduł biblioteki STL (ang. Standard Template Library - biblioteka standardowych szablonów). Opis STL znajdziesz w Wikipedii. My przejdziemy od razu do praktycznych zastosowań. Pierwszą klasą szablonową, którą omówimy będzie klasa vector. Klasa ta przypomina tablicę z języka C++ - składa sie z ciagu elementów tego samego typu, które są umieszczone obok siebie w jednym bloku pamięci. W stosunku do zwykłej tablicy klasa vector zawiera wiele ulepszeń.
Aby korzystać z tej klasy, musisz na początku swojego programu dodać wpis:
...
#include <vector>
...
|
Zmienną typu vector tworzy się w specyficzny sposób. Klasa szablonowa jest jakby pojemnikiem (kontenerem), który przechowuje dane pożądanego typu. Dlatego w trakcie tworzenia zmiennej musimy określić typ elementów zawartych w wektorze. Robimy to w sposób następujący:
vector<nazwa_typu_elementów>
nazwa_zmiennej;
Przykłady:
vector<int>
a; // vector a będzie
przechowywał elementy typu int |
Zmienna utworzona w powyższy sposób jest pustym wektorem - tzn. nie zawierającym żadnego elementu. Elementy dodajemy do wektora przy pomocy funkcji składowej:
wektor.push_back(wartość_nowego_elementu);
Dodany element zostaje umieszczony na końcu wektora. Rozmiar wektora rośnie o 1. Informacje o aktualnym rozmiarze otrzymujemy za pomocą funkcji:
wektor.size();
Informację o tym, czy wektor coś zawiera otrzymasz przy pomocy funkcji logicznej:
wektor.empty();
Zwraca ona false, jeśli w wektorze znajduje się jakiś element, a true w przypadku pustego wektora.
Możesz się zastanawiać w jaki sposób zachowana jest ciągłość obszaru pamięci zajmowanej przez wektor, skoro zwiększa on swój rozmiar. Otóż klasa rezerwuje na potrzeby przechowywania elementów pewien obszar pamięci - np. o pojemności 1000 elementów. Dopóki elementy wstawiane do wektora mieszczą się w tym obszarze, operacja push_back() przebiega bardzo szybko. Natomiast jeśli okaże się, iż nowy element już nie mieści się w starym obszarze, to klasa zarezerwuje w pamięci nowy obszar o takiej wielkości, aby pomieścił wszystkie stare elementy oraz rezerwę 1000 następnych. Stare elementy są przepisywane do nowego obszaru, a obszar poprzedni zostaje zwolniony do systemu.
Dostęp do elementów wektora uzyskujemy poprzez operator indeksowania [ ]:
wektor[numer_elementu]
lub przy pomocy funkcji składowej:
wektor.at(numer_elementu)
Operator [ ] nie sprawdza, czy podany indeks określa element leżący faktycznie w wektorze. Funkcja at() w przypadku wyjścia indeksu poza dozwoloną wartość dla danego wektora generuje wyjątek i zatrzymuje wykonywanie programu.
Poniższy program tworzy wektor dla liczb całkowitych typu int, umieszcza w nim dwadzieścia przypadkowych liczb z zakresu od 0 do 9 i wypisuje zawartość wektora po dodaniu każdej liczby. Liczby dodawane są na koniec wektora.
#include <iostream>
#include <vector>
using namespace std; main()
{
vector<int> V; // tworzymy pusty wektor
// inicjujemy generator liczb pseudolosowych
srand((unsigned)time(NULL)); // dodajemy 20 liczb pseudolosowych
while(V.size() < 20) { // dodajemy na koniec wektora nową liczbę pseudolosową V.push_back(rand() % 10); // wypisujemy zawartość wektora
for(int i = 0; i < V.size(); i++) cout << V[i] << " "; cout << endl; } cout << endl; system("PAUSE");
}
|
|
5 5 3 5 3 9 5 3 9 1 5 3 9 1 5 5 3 9 1 5 9 5 3 9 1 5 9 4 5 3 9 1 5 9 4 9 5 3 9 1 5 9 4 9 0 5 3 9 1 5 9 4 9 0 8 5 3 9 1 5 9 4 9 0 8 6 5 3 9 1 5 9 4 9 0 8 6 7 5 3 9 1 5 9 4 9 0 8 6 7 3 5 3 9 1 5 9 4 9 0 8 6 7 3 3 5 3 9 1 5 9 4 9 0 8 6 7 3 3 3 5 3 9 1 5 9 4 9 0 8 6 7 3 3 3 0 5 3 9 1 5 9 4 9 0 8 6 7 3 3 3 0 2 5 3 9 1 5 9 4 9 0 8 6 7 3 3 3 0 2 4 5 3 9 1 5 9 4 9 0 8 6 7 3 3 3 0 2 4 3 5 3 9 1 5 9 4 9 0 8 6 7 3 3 3 0 2 4 3 5 Aby kontynuować, naciśnij dowolny klawisz . . . |
Wektor możemy tworzyć od razu określając liczbę zawartych w nim elementów. W tym celu przy definicji zmiennej wykorzystujemy odpowiedni konstruktor wektora:
vector<typ_elementów>
nazwa_zmiennej(liczba_elementów);
lub
vector<typ_elementów>
nazwa_zmiennej(liczba_elementów,wartość_elementów);
Przykład:
vector<double>
V(100);
// zostanie utworzony wektor V 100 liczb typu double
// o początkowej wartości 0.0
vector<double>
V(100,15.25);
// zostanie utworzony wektor V 100 liczb typu double
// każda o wartości 15.25
#include <iostream> #include <vector> using namespace std; main() { vector<int> V(10); // tworzymy wektor 10 liczb // wyświetlamy zawartość wektora for(int i = 0; i < V.size(); i++) cout << V[i] << " "; cout << endl << endl; system("PAUSE"); } |
#include <iostream> #include <vector> using namespace std; main() { vector<int> V(10,15); // tworzymy wektor 10 liczb o wartości 15 // wyświetlamy zawartość wektora for(int i = 0; i < V.size(); i++) cout << V[i] << " "; cout << endl << endl; system("PAUSE"); } |
|
|
0 0 0 0 0 0 0 0 0 0 Aby kontynuować, naciśnij dowolny klawisz . . . |
15 15 15 15 15 15 15 15 15 15 Aby kontynuować, naciśnij dowolny klawisz . . . |
Dostęp do pierwszego elementu wektora uzyskujemy przy pomocy:
wektor[0]
// wykorzystujemy operator indeksowania
wektor.at(0)
// wykorzystujemy funkcję indeksową
wektor.front() // wykorzystujemy funkcję
składową
Dostęp do ostatniego elementu wektora uzyskujemy przy pomocy:
wektor[wektor.size()-1]
// wykorzystujemy operator indeksowania
wektor.at(wektor.size()-1) // wykorzystujemy funkcję
indeksową
wektor.back()
// wykorzystujemy funkcję składową
Poniższy program tworzy wektor 10 elementowy. Umieszcza w nim liczby losowe z przedziału od 0 do 9999. Wypisuje zawartość wektora oraz pierwszy i ostatni element.
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std; main()
{
vector<int> V; // tworzymy wektor
// inicjujemy generator liczb pseudolosowych
srand((unsigned)time(NULL)); // wektor wypełniamy 10 liczbami pseudolosowymi od 0 do 9999
while(V.size() < 10) V.push_back(rand() % 10000); // wyświetlamy zawartość wektora
for(int i = 0; i < V.size(); i++) cout << setw(5) << V[i]; // wyświetlamy pierwszy i ostatni element wektora
cout << endl << endl << "Pierwszy: " << setw(5) << V.front() << endl << "Ostatni : " << setw(5) << V.back() << endl << endl; system("PAUSE");
}
|
|
1027 6017 611 8215 3549 884 855 2231 7723 452 Pierwszy: 1027 Ostatni : 452 Aby kontynuować, naciśnij dowolny klawisz . . . |
Iterator jest obiektem wskazującym kolejne elementy przechowywane w kontenerze klasy. Możemy go przyrównać do wskaźnika, czyli zmiennej przechowującej adres danej docelowej. Jednakże, w porównaniu ze wskaźnikiem, iterator posiada dużo większą funkcjonalność. Iterator klasy vector tworzymy następująco:
vector<typ_elementów>::iterator
nazwa_zmiennej;
Przykład:
vector<int>::iterator
it_int; // tworzymy iterator
elementów typu int w kontenerze typu vector
Tak utworzony iterator nie wskazuje jeszcze żadnego elementu wektora. Musimy go odpowiednio zainicjować za pomocą funkcji składowych:
iterator =
wektor.begin(); // ustawienie
iteratora na pierwszy element wektora
iterator = wektor.end(); // ustawienie iteratora poza ostatni element wektora
Na iteratorach wektora można wykonywać następujące działania:
* iterator
// dostęp do elementu wskazywanego przez iterator
iterator++; // przesunięcie iteratora na następny element w wektorze
iterator--; // cofnięcie iteratora na poprzedni element w wektorze
iterator += n; // ustawienie iteratora na element leżący o n pozycji dalej w wektorze
iterator -= n; // ustawienie iteratora na element leżący o n pozycji wcześniej w wektorze
iterator1 - iterator2 // odległość pomiędzy pozycjami wskazywanymi przez iteratory
Poniższy program tworzy wektor 10 elementowy, wypełnia go liczbami pseudolosowymi z zakresu od 0 do 99, a następnie wypisuje zawartość wektora. Dostęp do elementów poprzez iterator.
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std; main()
{
vector<int> V(10); // tworzymy wektor 10 elementowy
vector<int>::iterator i; // tworzymy iterator do elementów wektora
// inicjujemy generator liczb pseudolosowych
srand((unsigned)time(NULL)); // wektor wypełniamy 10 liczbami pseudolosowymi od 0 do 99
for(i = V.begin(); i != V.end(); i++) * i = rand() % 100; // wyświetlamy zawartość wektora
for(i = V.begin(); i != V.end(); i++) cout << setw(3) << * i; cout << endl << endl; system("PAUSE");
}
|
|
72 27 89 23 88 58 50 49 1 16 Aby kontynuować, naciśnij dowolny klawisz . . . |
Z końca wektora usuwamy elementy za pomocą funkcji:
wektor.pop_back();
Funkcja nie zwraca żadnej wartości. Jeśli chcesz pobrać element z końca wektora, to najpierw należy użyć funkcji wektor.back(), która udostępni ostatni element, a po jego przetworzeniu dopiero stosuje się wektor.pop_back(). Poniższy program tworzy wektor. Wypełnia go 10-cioma liczbami pseudolosowymi, a następnie usuwa kolejne elementy od końca.
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std; main()
{
vector<int> V; // tworzymy wektor
// inicjujemy generator liczb pseudolosowych
srand((unsigned)time(NULL)); // wektor wypełniamy 10 liczbami pseudolosowymi od 0 do 9999
while(V.size() < 10) V.push_back(rand() % 10000); // wyświetlamy zawartość wektora i usuwamy kolejne od końca elementy
while(!V.empty()) { for(int i = 0; i < V.size(); i++) cout << setw(5) << V[i]; cout << endl; V.pop_back(); } cout << endl << endl; system("PAUSE");
}
|
|
2037 9273 2927 4951 5251 4117 730 2427 2841 506 2037 9273 2927 4951 5251 4117 730 2427 2841 2037 9273 2927 4951 5251 4117 730 2427 2037 9273 2927 4951 5251 4117 730 2037 9273 2927 4951 5251 4117 2037 9273 2927 4951 5251 2037 9273 2927 4951 2037 9273 2927 2037 9273 2037 Aby kontynuować, naciśnij dowolny klawisz . . . |
Jeśli usuwany element znajduje się wewnątrz wektora, to używamy funkcji:
wektor.erase(iterator);
// usuwa element na pozycji wskazywanej przez iterator
wektor.erase(i_początek,
i_koniec);
// usuwa elementy od pozycji iteratorów i_początek do elementu
// poprzedzającego pozycję i_koniec
Funkcja erase() zwraca iterator do elementu, który w wektorze znajdował się bezpośrednio za usuniętym elementem.
Poniższy program tworzy wektor. Wypełnia go 10-cioma liczbami pseudolosowymi, a następnie usuwa kolejne elementy od początku wektora.
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std; main()
{
vector<int> V; // tworzymy wektor
// inicjujemy generator liczb pseudolosowych
srand((unsigned)time(NULL)); // wektor wypełniamy 10 liczbami pseudolosowymi od 0 do 9999
while(V.size() < 10) V.push_back(rand() % 10000); vector<int>::iterator i; // tworzymy iterator i = V.begin(); // iterator ustawiamy na pierwszy element // wyświetlamy zawartość wektora // i usuwamy kolejne od początku elementy while(!V.empty()) { for(int j = 0; j < V.size(); j++) cout << setw(5) << V[j]; cout << endl; V.erase(i); } cout << endl << endl; system("PAUSE"); } |
|
6413 4218 277 6079 1453 3055 9878 2039 9972 6863 4218 277 6079 1453 3055 9878 2039 9972 6863 277 6079 1453 3055 9878 2039 9972 6863 6079 1453 3055 9878 2039 9972 6863 1453 3055 9878 2039 9972 6863 3055 9878 2039 9972 6863 9878 2039 9972 6863 2039 9972 6863 9972 6863 6863 Aby kontynuować, naciśnij dowolny klawisz . . . |
Zawartość całego wektora usuwamy przy pomocy funkcji:
.clear();wektor
Wstawianie nowych elementów do wnętrza wektora realizujemy przy pomocy funkcji składowej:
wektor.insert(iterator,wartość);
// na pozycji iteratora zostaje umieszczona wartość
wektor.insert(iterator,ilość,wartość); // na pozycji iteratora zostaje umieszczona wartość podaną ilość razy
wektor.insert(i_gdzie,i_od,i_do); // na pozycji iteratora i_gdzie wstawia zawartość wektora wskazywanego
// przez iteratory i_od oraz i_do. Elementy wektora wstawiane są
// począwszy od i_od, a skończywszy przes i_do.
Tylko pierwsza z wersji funkcji wektor.insert() zwraca iterator wskazujący wstawiony do wektora element. Pozostałe nie zwracają żadnej wartości.
Sposób wykorzystania funkcji wektor.insert(). Tworzy on wektor 10 elementowy, a następnie wstawia do niego jeden element, pięć elementów oraz 8 elementów z innego wektora.
#include <iostream> #include <iomanip> #include <vector> using namespace std; main() { vector<int> V1(10,5); // tworzymy wektor 10 elementowy vector<int> V2(10); // tworzymy wektor 10 elementowy vector<int>::iterator i_od,i_do; // inicjujemy V2 kolejnymi liczbami od 0 do 9 for(int i = 0; i < V2.size(); i++) V2[i] = i; // wyświetlamy zawartość wektora V1 for(int i = 0; i < V1.size(); i++) cout << setw(2) << V1[i]; cout << endl << endl; // wstawiamy element 2 na pozycji 5 w V1 V1.insert(V1.begin() + 5,2); for(int i = 0; i < V1.size(); i++) cout << setw(2) << V1[i]; cout << endl << endl; // wstawiamy 5 elementów 1 od pozycji 3 w V1 V1.insert(V1.begin() + 3,5,1); for(int i = 0; i < V1.size(); i++) cout << setw(2) << V1[i]; cout << endl << endl; // wstawiamy 8 pierwszych elementów V2 do V1 od pozycji 2 i_od = V2.begin(); i_do = i_od + 8; V1.insert(V1.begin() + 2,i_od,i_do); for(int i = 0; i < V1.size(); i++) cout << setw(2) << V1[i]; cout << endl << endl; system("PAUSE"); } |
|
5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 2 5 5 5 5 5 5 5 5 1 1 1 1 1 5 5 2 5 5 5 5 5 5 5 0 1 2 3 4 5 6 7 5 1 1 1 1 1 5 5 2 5 5 5 5 5 Aby kontynuować, naciśnij dowolny klawisz . . . |