Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Autor: 'Pietrzuch'
Biblioteki C++

Kontener tablicy (std::vector)

[lekcja] 5. Kontener tablicy (std::vector).

Dokumentacja kontenera vector

Kompletna dokumentacja kontenera » standard C++vector w języku polskim znajduje się na łamach niniejszego serwisu w dziale dokumentacji.

Co to jest vector?

Vector jest to tak zwany kontener na dane(pojemnik), inaczej dynamiczna tablica. W owej tablicy mamy dostęp do każdego jej elementu oraz możemy w każdym momencie zwiększać jej wielkość.

Jakimi funkcjami posługujemy się używając vectora?

  • push_back() - dodaje do końca tablicy nowy element podany w nawiasie
  • insert() - dodaje element do dynamicznej tablicy w podanym miejscu
  • begin() - wskazuje pierwszy element dynamicznej tablicy
  • end() - wskazuje na koniec dynamicznej tablicy
  • size() - zwraca ilość elementów tablicy

Pierwszy program używający vector'a.

Kod przykładowego programu:
C/C++
#include <iostream>
#include <vector>

int main()
{
    std::vector < int > tab;
    //zapis
    int x = 0;
    for( int i = 0; i < 10; i++ )
    {
        tab.push_back( x );
        x = x + 2;
    }
    //odczyt
    for( int i = 0; i < tab.size(); i++ )
    {
        std::cout << tab[ i ] << std::endl;
    }
    return 0;
}
A teraz o co w tym wszystkim chodzi:
C/C++
#include <vector>
Nagłówek zawierający vector zawsze musimy napisać tą linijkę zanim rozpoczniemy pracę z dynamicznymi tablicami.
C/C++
int x = 0;
for( int i = 0; i < 10; i++ )
{
    tab.push_back( x );
    x = x + 2;
}
Najpierw deklarujemy zmienną o nazwie x, którą będzie zapełniany nasz Vector. Następnie rozpoczyna się pętla mająca 10 obrotów. Funkcja push_back rozszerza naszą tablicę na końcu o jeden jej element, a następnie wpisuje do niego wartość podaną w nawiasie.
C/C++
for( int i = 0; i < tab.size(); i++ )
{
    std::cout << tab[ i ] << std::endl;
}
Tutaj znów rozpoczynamy pętlę. Następnie odczytujemy wartości dynamicznej tablicy, a z pomocą przychodzi nam funkcjia size() zwracająca jej wielkość. Warto zauważyć, iż odczyt dynamicznej tablicy odbywa się w taki sam sposób jak i zwykłej tablicy.
C/C++
return 0;
}
I tu kończymy nasz program linijką return 0 i nawiasem.

Zapisywanie danych do pojemnika

C/C++
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>

int main()
{
    std::vector < int > tab;
    srand( time( NULL ) );
    //zapis
    tab.push_back( 0 );
    for( int i = 0; i < 10; i++ )
    {
        int gdzie = rand() % tab.size();
        tab.insert( tab.begin() + gdzie, i );
    }
    //odczyt
    for( int i = 0; i < tab.size(); i++ )
    {
        std::cout << tab[ i ] << std::endl;
    }
    return 0;
}
Tłumaczenie:
C/C++
int gdzie = rand() % tab.size();
tab.insert( tab.begin() + gdzie, i );
Najpierw losujemy liczbę, którą później wykorzystujemy do wybrania odpowiedniego miejsca dla zapisu zmiennej i. Widzimy funkcję insert(), jest ona nieco czasochłonna jednak w wielu wypadkach niezastąpiona. Otóż musi ona najpierw rozszerzyć tablicę, następnie przesunąć określone elementy w następne miejsce, a dopiero na końcu zapisuje podaną wartość do pustego elementu tablicy. Bardzo ważna jest też funkcja tab.begin() wskazująca na pierwszy element tablicy. Bez niej nasz program by się nie skompilował. Do dyspozycji zamiast tab.begin() mamy, także funkcję tab.end() wskazującą na ostani element tablicy. Ważne jest też by przed użyciem tych dwóch funkcji tablica miała chociaż jeden element. Jeżeli nie będzie go posiadać zaraz po uruchomieniu naszej aplikacji, program zamknie się lub zawiesi.

Sortowanie zawartości kontenerów z użyciem algorithm

Użyjemy kodu z poprzedniego programu, a więc:
C/C++
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <ctime>

int main()
{
    std::vector < int > tab;
    srand( time( NULL ) );
    //zapis
    tab.push_back( 0 );
    for( int i = 0; i < 10; i++ )
    {
        int gdzie = rand() % tab.size();
        tab.insert( tab.begin() + gdzie, i );
    }
    //odczyt
    sort( tab.begin(), tab.end() );
    for( int i = 0; i < tab.size(); i++ )
    {
        std::cout << tab[ i ] << std::endl;
    }
    return 0;
}
Nie ma co wiele tłumaczyć jedynie dwie linijki:
C/C++
#include <algorithm>
Tutaj znajduje się dla nas ważna funkcja sort(), więc jeżeli chcemy jej używać musimy dodać tą linijkę.
C/C++
sort( tab.begin(), tab.end() );
Funkcja sort() sortuje zawartość kontenera, w parametrach podajemy funkcje wskazujące na odpowiednie miejsca w pojemniku przeznaczone do sortowania. Zazwyczaj jest to początek i koniec, jednak możemy zastosować cos takiego:
C/C++
sort( tab.begin() + 5, tab.end() );

Tworzenie tablicy obiektow własnej klasy

Vector umożliwia nam też tworzenie pojemnika obiektów naszej własnej klasy. Powinieneś, a właściwie musisz znać klasy, oraz konstruktory w c++, aby prawidłowo zrozumieć tą część artykułu. Artykuł o klasach w C++. Artkuł o konstruktorach klasy w C++.
Oto przykład, kod:
C/C++
#include <iostream>
#include <vector>
#include <string>
#include <conio.h>

using namespace std;


class czlowiek
{
public:
    string imie;
    string nazwisko;
    string numer;
    czlowiek( string ximie, string xnazwisko, string xnumer );
};

int main()
{
    vector < czlowiek > osoba;
    cout << "Baza Osob\n1.-Lista osob\n2.-Dodaj osobe\n3.-Wyjscie";
    char odp;
    do
    {
        odp = getch();
        switch( odp )
        {
        case '1':
            cout << "\n\n\nLista osob:\n";
            for( int i = 0; i < osoba.size(); i++ )
            {
                cout << endl;
                cout << "Nazwa: " << osoba[ i ].imie << endl;
                cout << "Autor: " << osoba[ i ].nazwisko << endl;
                cout << "Numer tel.: " << osoba[ i ].numer << endl;
            }
            break;
        case '2':
            cout << "\n\n\n|----DODAWANIE_OSOBY_DO_LISTY-----|";
            cout << "\nPodaj imie: ";
            string odp_imie;
            cin >> odp_imie;
            cout << "Nazwisko: ";
            string odp_nazwisko;
            cin >> odp_nazwisko;
            cout << "Numer tel.: ";
            string odp_numer;
            cin >> odp_numer;
            osoba.push_back( czlowiek( odp_imie, odp_nazwisko, odp_numer ) );
            cout << "\n<***ZAKONCZONO_Z_SUKCESEM***>";
            break;
        }
    } while( odp != '3' );
   
    return 0;
}

czlowiek::czlowiek( string ximie, string xnazwisko, string xnumer )
    : imie( ximie )
     , nazwisko( xnazwisko )
     , numer( xnumer )
{
}
Kod powyżej pokazuje użycie kontenerów w praktyce. Myślę, że Ci się przyda, gdyż najważniejsze jest to by umieć czegoś używać pisząc swój projekt.

Więcej o funkcjach vectora

Teraz przedstawię program zawierający funkcje które też są bardzo ważne, a ich wcześniej nie przedstawiłem:
C/C++
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using namespace std;

int main()
{
    vector < int > tab;
    srand( time( NULL ) );
    for( int i = 0; i < 12; i++ )
         tab.push_back( rand() % 100 );
   
    sort( tab.begin(), tab.end() );
    //odczytywanie
    cout << "Pojemnik przed edycja: \n";
    for( int i = 0; i < tab.size(); i++ )
         cout << tab[ i ] << std::endl;
    //pop_back
    tab.pop_back();
    cout << "\nPojemnik po wywolaniu funkcji pop_back: \n";
    for( int i = 0; i < tab.size(); i++ )
         cout << tab[ i ] << std::endl;
    //resize
    tab.resize( 8 );
    cout << "\nPojemnik po wywolaniu funkcji resize: \n";
    for( int i = 0; i < tab.size(); i++ )
         cout << tab[ i ] << std::endl;
    //erase
    cout << "\nTrzeci element tablicy przed erase: " << tab[ 2 ] << "\n";
    tab.erase( tab.begin() + 2 );
    cout << "Trzeci element tablicy po erase: " << tab[ 2 ] << "\n";
    //erase cdn.
    cout << "\nTablica przed erase z dwoma parametrami:\n";
    for( int i = 0; i < tab.size(); i++ )
         std::cout << tab[ i ] << std::endl;
   
    tab.erase( tab.begin() + 1, tab.begin() + 4 );
    cout << tab.size();
    cout << "\nTablica po erase z dwoma parametrami:\n";
    for( int i = 0; i < tab.size(); i++ )
         cout << tab[ i ] << std::endl;
    //clear
    tab.clear();
    cout << "\nZawartosc pojemnika po clear: \n";
    for( int i = 0; i < tab.size(); i++ )
         cout << tab[ i ] << std::endl;
   
    return 0;
}
Tłumaczenie:
C/C++
for( int i = 0; i < 12; i++ )
     tab.push_back( rand() % 100 );

sort( tab.begin(), tab.end() );
//odczytywanie
cout << "Pojemnik przed edycja: \n";
for( int i = 0; i < tab.size(); i++ )
     cout << tab[ i ] << std::endl;

Zapełniamy tablicę losowymi elementami, później sortujemy ich wartość.
Na końcu wyświetlamy zawartość pojemnika.
C/C++
tab.pop_back();
cout << "\nPojemnik po wywolaniu funkcji pop_back: \n";
for( int i = 0; i < tab.size(); i++ )
     cout << tab[ i ] << std::endl;

Jak widzimy funkcja pop_back() usuwa ostatni element dynamicznej tablicy.
C/C++
//resize
tab.resize( 8 );
cout << "\nPojemnik po wywolaniu funkcji resize: \n";
for( int i = 0; i < tab.size(); i++ )
     cout << tab[ i ] << std::endl;

Funkcja resize() zmienia wielkość vectora do podanej w nawiasie.
C/C++
//erase
cout << "\nTrzeci element tablicy przed erase: " << tab[ 2 ] << "\n";
tab.erase( tab.begin() + 2 );
cout << "Trzeci element tablicy po erase: " << tab[ 2 ] << "\n";
Funkcja erase() z podanym jednym parametrem, czyli adresem określonego elementu, usuwa go. Pamiętajmy że begin()+3 nie oznacza 3 elementu, a 4 ponieważ sama funkcja begin zwraca iterator do 1 elementu.

UWAGA! Elementy znajdujące się za elementem usuniętym zostaną przesunięte
odpowiedno na jego miejsce.
C/C++
//erase cdn.
cout << "\nTablica przed erase z dwoma parametrami:\n";
for( int i = 0; i < tab.size(); i++ )
     std::cout << tab[ i ] << std::endl;

tab.erase( tab.begin() + 1, tab.begin() + 4 );
cout << tab.size();
cout << "\nTablica po erase z dwoma parametrami:\n";
for( int i = 0; i < tab.size(); i++ )
     cout << tab[ i ] << std::endl;

Funkcji erase() można też używać podając dwa parametry. Zostaje wtedy usunięty
ciąg elementów pomiędzy podanymi adresami wraz z podanymi adresami.
C/C++
//clear
tab.clear();
cout << "\nZawartosc pojemnika po clear: \n";
for( int i = 0; i < tab.size(); i++ )
     cout << tab[ i ] << std::endl;

return 0;
}
Funkcja clear() całkowicie czyści tablicę nie zostawiając w niej żadnego elementu.

Iterator w dynamicznej talicy

Co to jest iterator

Iterator w vectorze jest to swego rodzaju wskaźnik wskazujący na określony element tablicy. Możemy go edytować oraz z jego pomocą odwoływać się do określonego elementu tablicy.

Kiedy go używamy?

Iteratora w vectorze używamy do wskazywania na określony element tablicy.
Używaliśmy już iteratora w naszych programach m.in funkcja begin() zwraca iterator do pierwszego elementu tablicy.

Przykładowy program używający iteratora

C/C++
#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector < int > tab;
    for( int i = 0; i < 10; i++ )
         tab.push_back( i );
   
    vector < int >::iterator it_tab = tab.begin();
    for(; it_tab != tab.end(); it_tab++ )
         cout <<* it_tab;
   
}
Tłumaczenie:
C/C++
vector < int >::iterator it_tab = tab.begin();
for(; it_tab != tab.end(); it_tab++ )
     cout <<* it_tab;

Na początku deklarujemy i definiujemy nasz iterator. Następnie z pomocą pętli for i iterator odczytujemy dane naszej tablicy. Warto zauważyć, że można łatwo zmieniać adres na który wskazuje nasz iterator dodawaniem itp. Iteratorem posługujemy się podobnie jak wskaźnikiem o czym świadczy gwiazdeczka. ;)

Zakończenie

Zakończyliśmy już lekcję o vectorze, jednym z bardziej przydatnych narzędzi STL-a. Teraz będziesz mógł pisać swoje programy nie określając z góry wielkości tablicy.
Poprzedni dokument Następny dokument
Adapter kolejki priorytetowej (std::priority_queue) Kurs WinAPI, C++