Vector ( std::vector<T>) on standardi C++:n yleinen ohjelmointimalli, joka toteuttaa dynaamisen taulukon .
Malli vectorsijaitsee otsikkotiedostossa <vector>. Kuten kaikki vakiokomponentit , se sijaitsee . Tämä käyttöliittymä emuloi tavallisen Cstd - taulukon toimintaa (esimerkiksi nopeaa satunnaista pääsyä elementteihin) sekä joitain lisäominaisuuksia, kuten vektorin automaattista koon muutosta, kun elementtejä lisätään tai poistetaan.
Vektorin kaikkien elementtien on oltava samaa tyyppiä. Et esimerkiksi voi tallentaa char- ja int -tietoja yhdessä samaan vektoriinstanssiin. Luokassa vector on vakiomenetelmät elementtien käyttämiseen, elementtien lisäämiseen ja poistamiseen sekä tallennettavien elementtien määrän hankkimiseen.
Vektori voidaan alustaa millä tahansa tyypillä, jolla on kopiokonstruktori ja joka on määritelty operator=ja täyttää seuraavat ehdot [1] :
Ilmaisu | palautustyyppi | Kunto |
---|---|---|
t = u | T& | tvastaavau |
T(t) | tvastaavaT(t) | |
T(u) | uvastaavaT(u) | |
&u | const T* | näyttää osoitettau |
t.~T() |
Tässä T on tyyppi, jolla vektori alustetaan, t on tyypin muuttuja T, u on tyypin muuttuja (mahdollisesti const) T.
Esimerkiksi:
vektori < int > myVector ; // Tyhjä vektori elementeistä, joiden tyyppi on int vector < float > myVector ( 10 ); // 10:n vektori leijuttaa vektorin < char > myVector ( 5 , ' ' ); // Vektori, joka koostuu 5 välilyönnistä luokka T { ... }; int n = 10 ; vektori < T > myVektori ( n ); // 10 mukautetun tyypin T elementin vektoriVektorin yksittäistä elementtiä voidaan käyttää alla olevassa taulukossa kuvattujen toimintojen avulla. C- ja C++- käytännön mukaan ensimmäisellä elementillä on indeksi 0ja viimeisellä elementillä indeksi size() - 1[2] .
Ilmaisu | palautustyyppi | Rajatarkastus? |
---|---|---|
v.at(i) | T&tai const T&elementille i | Poikkeuksen tekeminen on mahdollistaout_of_range |
v[i] | T&tai const T&elementille i | Määrittelemätön käyttäytyminen milloini >= v.size() |
v.front() | T&tai const T&ensimmäiselle elementille | Määrittelemätön käyttäytyminen milloinv.empty() == true |
v.back() | T&tai const T&viimeiselle elementille | Määrittelemätön käyttäytyminen milloinv.empty() == true |
Missä v on objekti tyyppiä (mahdollisesti const) vector<T>ja i on vektorin vaaditun elementin indeksi.
Luokka vector on kontti. C++-standardin mukaan minkä tahansa säiliön tulee sisältää menetelmät begin(), end(), size(), max_size(), empty(), ja swap().
Alla on lyhyt luettelo käytettävissä olevista menetelmistä kuvauksen ja monimutkaisuuden osoituksella .
Menetelmä | Kuvaus | Monimutkaisuus | |
---|---|---|---|
Rakentajat | vector::vector | Oletuskonstruktori. Ei ota argumentteja, luo uuden vektorin esiintymän | O(1)(suorittaa vakioajassa) |
vector::vector(const vector& c) | Oletuskopiointikonstruktori. Luo vektorista kopionc | O(n)(toimii lineaarisessa ajassa, joka on verrannollinen vektorin kokoon c) | |
vector::vector(size_type n, const T& val = T()) | Luo vektorin nobjekteista. Jos valilmoitettu, jokainen näistä objekteista alustetaan sen arvolla; muuten objektit saavat oletuskonstruktoriarvon tyyppiä T. | O(n) | |
vector::vector(input_iterator start, input_iterator end) | Luo elementtien vektorin välillä startjaend | O(n) | |
Tuhoaja | vector::~vector | Tuhoaa vektorin ja sen elementit | |
Operaattorit | vector::operator= | Kopioi yhden vektorin arvon toiseen. | O(n) |
vector::operator== | Kahden vektorin vertailu | O(n) | |
Pääsy elementteihin |
vector::at | Elementin käyttö rajojen ulkopuolisella tarkistuksella | O(1) |
vector::operator[] | Tietyn elementin käyttö | O(1) | |
vector::front | Pääsy ensimmäiseen elementtiin | O(1) | |
vector::back | Pääsy viimeiseen elementtiin | O(1) | |
Iteraattorit | vector::begin | Palauttaa iteraattorin vektorin ensimmäiseen elementtiin | O(1) |
vector::end | Palauttaa iteraattorin vektorin viimeisen elementin jälkeen | O(1) | |
vector::rbegin | Palaa reverse_iteratornykyisen vektorin loppuun. | O(1) | |
vector::rend | Palaa reverse_iteratorvektorin alkuun. | O(1) | |
Työskentely vektorin koon kanssa |
vector::empty | Palauttaa true, jos vektori on tyhjä | O(1) |
vector::size | Palauttaa vektorin elementtien määrän | O(1) | |
vector::max_size | Palauttaa suurimman mahdollisen määrän elementtejä vektorissa | O(1) | |
vector::reserve | Asettaa vektorin elementtien vähimmäismäärän | O(n) | |
vector::capacity | Palauttaa elementtien määrän, jonka vektori voi sisältää, ennen kuin sen on varattava lisää tilaa. | O(1) | |
vector::shrink_to_fit | Vähentää käytetyn muistin määrää vapauttamalla käyttämätöntä muistia ( C++11 ) | O(1) | |
Muokkaimet | vector::clear | Poistaa kaikki vektorin elementit | O(n) |
vector::insert | Elementtien lisääminen vektoriin | Lisäys lopussa edellyttäen, että muistia ei jaeta uudelleen - O(1), mielivaltaiseen paikkaan -O(n) | |
vector::erase | Poistaa määritetyt vektorielementit (yksi tai useampi) | O(n) | |
vector::push_back | Elementin lisääminen vektorin loppuun | O(1) | |
vector::pop_back | Poista vektorin viimeinen elementti | O(1) | |
vector::resize | Muuttaa vektorin kokoa annetulla määrällä | O(n) | |
vector::swap | Vaihda kahden vektorin sisältö | O(1) | |
Muut menetelmät | vector::assign | Yhdistää annetut arvot vektoriin | O(n), jos haluttu vektorin koko on asetettu, O(n*log(n))muistia uudelleenallokoitaessa |
vector::get_allocator | Palauttaa muistin varaamiseen käytetyn allokaattorin | O(1) |
Yllä kuvattujen suorien elementtien käyttötoimintojen lisäksi vektorin elementteihin pääsee käsiksi iteraattoreilla .
Iteraattoreita käytetään yleensä pareittain, joista toista käytetään osoittamaan nykyinen iteraatio ja toista käytetään osoittamaan säiliön loppua. Iteraattorit luodaan vakiomenetelmillä, begin()kuten end(). Funktio begin()palauttaa osoittimen ensimmäiseen elementtiin ja palauttaa osoittimen viimeistä seuraavaan end() kuvitteelliseen olemattomaan elementtiin.
Vektori käyttää ominaisuuksiltaan monipuolisinta iteraattorityyppiä, RandomAccessIterator (random access iterator), jonka avulla voit kulkea kontin läpi missä tahansa järjestyksessä sekä muuttaa vektorin sisältöä läpikulkuprosessin aikana. Jos vektori kuitenkin muuttuu, iteraattori voi muuttua virheelliseksi.
Esimerkki vektorielementtien summan laskemisesta iteraattoreilla:
#include <iostream> #sisällytä <vektori> #include <iteraattori> käyttäen nimiavaruutta std ; int main () { vektori < int > vektori ; vektori < int >:: iteraattori the_iterator ; for ( int i = 0 ; i < 10 ; i ++ ) { the_vektori . push_back ( i ); } kokonaissumma = 0 ; _ the_iterator = the_vektori . alkaa (); while ( the_iterator != the_vector . end ()) { yhteensä += * iteraattori ++ ; } cout << "summa= " << yhteensä << endl ; paluu 0 ; } vektori < int > vektori ; vektori < int >:: iteraattori the_iterator ; for ( int i = 0 ; i < 10 ; i ++ ) { the_vektori . push_back ( i ); } kokonaissumma = 0 ; _ the_iterator = the_vektori . alkaa (); while ( the_iterator != the_vector . end ()) { yhteensä += * iteraattori ; /* Huomaa, että elementtiin pääsee käsiksi poistamalla viittaus iteraattoriin */ ++ the_iterator ; } cout << "Yhteensä=" << yhteensä << endl ;Tulos:
Yhteensä = 45
Tyypillinen vektoritoteutus on osoitin dynaamiseen taulukkoon. Vektorin koko on elementtien todellinen lukumäärä, ja koko on sen käyttämän muistin määrä.
Jos uusia elementtejä lisättäessä vektoriin sen koko tulee suurempi kuin sen tilavuus, muisti varataan uudelleen. Tyypillisesti tämä saa vektorin varaamaan uuden tallennusalueen, siirtämään elementit ja vapauttamaan vanhat alueet uuteen muistipaikkaan.
Koska elementtien osoitteet muuttuvat tämän prosessin aikana, kaikki vektorin elementtien viittaukset tai iteraattorit voivat muuttua kelpaamattomiksi. Virheellisten viitteiden käyttö johtaa määrittelemättömään toimintaan. Esimerkki:
#sisällytä <vektori> int main () { std :: vektori < int > v ( 1 ); // Luo vektori yhdellä int-elementillä, jonka arvo on 0 int & ensimmäinen = * v . alkaa (); // Luo linkki ensimmäiseen elementtiin v . insert ( v . end (), v . kapasiteetti (), 0 ); // Lisää uusia elementtejä int i = ensimmäinen ; // Määrittelemätön käyttäytyminen. Linkki ei ehkä ole kelvollinen }Menetelmää reserve()käytetään turhan muistin uudelleenallokoinnin estämiseen. Kutsumisen reserve(n)jälkeen vektorin koko on taatusti vähintään n. Esimerkki:
#sisällytä <vektori> int main () { std :: vektori < int > v ( 1 ); // Luo vektori, joka koostuu yhdestä int-tyypin elementistä, jonka arvo on 0 v . reservi ( 10 ); // Varaa tila int & first = * v . alkaa (); // Luo linkki ensimmäiseen elementtiin v . lisää ( v . loppu (), 5 , 0 ); // Elementtien lisääminen vektoriin int i = ensimmäinen ; // OK, koska muistia ei jaettu uudelleen }Vektori ylläpitää tiettyä elementtijärjestystä siten, että kun uusi elementti lisätään vektorin alkuun tai keskelle, seuraavat elementit siirretään taaksepäin niiden osoitusoperaattorin ja kopiokonstruktorin suhteen. Siksi lisäyskohdan jälkeiset elementtiviittaukset ja iteraattorit mitätöidään. Esimerkki:
#sisällytä <vektori> int main () { std :: vektori < int > v ( 2 ); // Luo vektori, joka koostuu kahdesta Int-tyypin elementistä // Luo viittaukset molempiin elementteihin int & first = v . edessä (); int & last = v . takaisin (); v . insert ( v . alkaa () + 1 , 1 , 1 ); // Lisää uusia elementtejä vektorin keskelle int i = ensimmäinen ; // Määrittämätön toiminta, jos lisäys aiheutti uudelleenallokoinnin int j = viimeinen ; // Määrittelemätön toiminta C++-standardin §23.2.4.3/1 mukaisesti }C++-standardikirjasto määrittelee vektorimallien erikoistumisen bool. Erikoistumisen mukaan vektorin tulee pakata elementit siten, että jokainen tyypin elementti bооlkäyttää vain yhtä bittiä muistia [3] . Monet kutsuvat tätä bugiksi [4] [5] , koska se ei täytä C++ Standard Libraryvector<bool> -säilön vaatimuksia . Säilön on esimerkiksi oltava tosi tyyppiä T. Tämä ei päde c:n tapauksessa , joka on paikkamerkki , joka muunnetaan muotoon [6] . Sitä paitsi, ei anna viittauksella. C++-standardointikomitean ja kirjaston kehitystiimin välillä on sopimus, jonka mukaan se tulee poistaa käytöstä ja sitten poistaa vakiokirjastosta , jolloin toiminnallisuus palautetaan, mutta eri nimellä. [7]<T>::referencelvaluevector<bool>::referenceboolvector<bool>::iteratorbool&vector<bool>
Vektoria käyttävien C++- ohjelmien tulee sisältää otsikkotiedosto <vector>:
#sisällytä <vektori> // Tämän jälkeen voit alustaa muuttujan std :: vector < T > myVector ;Tässä T - säilöön tallennettavien tietojen tyyppi ja myVector - käytettävä muuttuja. Tvoi olla mikä tahansa tietotyyppi, mukaan lukien käyttäjän määrittämä tietotyyppi.
C : ssä ja C++ : ssa taulukko on dataa vierekkäisissä muistilohkoissa. Jokaiselle lohkolle määritetään sitten indeksi, ja kunkin lohkon sisältö voidaan löytää tuntemalla sen indeksi. Kaikkien taulukon elementtien on oltava samaa tyyppiä.
Vektori on samanlainen kuin dynaaminen taulukko, mutta vektori voi muuttaa itsensä kokoa. Muistia ei myöskään tarvitse vapauttaa manuaalisesti.
Koska vektorin elementit tallennetaan vierekkäin, vektorin ensimmäisen elementin osoite voidaan välittää funktiolle taulukkona (osoitin ensimmäiseen elementtiin). Seuraava esimerkki havainnollistaa, kuinka vektoria voidaan käyttää C-standardin kirjastofunktioiden memcpyja printf:
#include <cstring> // memcpy #sisällytä <vektori> #include <cstdio> // printf int main () { käyttäen nimiavaruutta std ; const char arr [] = "1234567890" ; // Luo vektori, jossa on 11 '\0'- vektoria < char > vec ( sizeof arr ); // Kopioi 11 elementtiä tyyppiä 'char' vektorimuistiin ( vec . data ( ), arr , sizeof arr ); // Tulostaa "1234567890" printf ( "%s" , vec . data ()); }Huomaa, että memcpyja printfei ole suositeltavaa käyttää turvallisempia vaihtoehtoja C++ Standard Librarysta
Seuraava esimerkki esittelee erilaisia tekniikoita, jotka sisältävät vektorin ja C++-standardikirjastoalgoritmeja , kuten sekoittamisen, lajittelun, suurimman elementin löytämisen ja poistamisen vektorista käyttämällä pyyhi-poisto-idiomia.
#include <iostream> #sisällytä <vektori> #include <algoritm> // sort, max_element, random_shuffle, remove_if, low_bound #include <functional> // suurempi, bind2nd // Käytetään mukavuuden vuoksi. Käytä oikeissa ohjelmissa varovasti käyttämällä nimiavaruutta std ; int main () { int arr [ 4 ] = { 1 , 2 , 3 , 4 }; // Alusta vektori käyttämällä taulukkovektoria < int > numerot ( arr , arr + 4 ); // Lisää numeroita lukuvektoriin . push_back ( 5 ); numerot . push_back ( 6 ); numerot . push_back ( 7 ); numerot . push_back ( 8 ); // Nyt vektori näyttää tältä: {1, 2, 3, 4, 5, 6, 7, 8} // Sekoita elementit satunnaisesti random_shuffle ( numerot . alkaa (), numerot . loppu ()); // Hanki maksimielementti, monimutkaisuus O(n) vektori < int >:: const_iterator suurin = max_element ( numerot . alkaa (), numerot . loppu () ); cout << "suurin elementti" << * suurin << endl ; cout << "Tämän elementin indeksi" << suurimmat - numerot . alkaa () << endl ; // Lajittele alkiot, monimutkaisuus O(n log n) lajittelu ( numerot . alku (), numerot . loppu ()); // Etsi luvun 5 sijainti vektorista, kompleksisuus O(log n) vektori < int >:: const_iterator five = alaraja ( numerot . alkaa (), numerot . loppu (), 5 ); cout << "Numero 5 on indeksissä " << viisi numeroa . alkaa () << endl ; // Poista kaikki elementit, jotka ovat suurempia kuin 4 numeroa . erase ( poista_jos ( numerot . alkaa (), numerot . loppu (), bind2nd ( suurempi < int > (), 4 )), numerot . loppu () ); // Tulosta loput for ( vektori < int >:: const_iterator it = numerot . alkaa (); it != numerot . end (); ++ it ) { cout << * se << ' ' ; } paluu 0 ; }Tulos sisältää:
Suurin elementti 8
Tämän elementin indeksi on 6 (toteutuksesta riippuvainen)
Numero 5 sijaitsee indeksin 4 alla
1 2 3 4
Esimerkki 2-ulotteisesta dynaamisesta vektorista sekä esimerkki sen käyttämisestä ja muokkaamisesta
typedef std :: vektori < std :: vektori < int > > pxMP ; void function () { int kokoX , kokoY ; // määritä koko lennossa. pxMP pxMap ( kokoX , std :: vektori < int > ( kokoY )); // joukko X/Y-pikseleitä 0.1. pxMap [ 0 ][ 5 ] = 1 ; /* pääsy */ // poista pxMap -sovelluksen vasen ja oikea sarake . pop_back (); pxMap . pyyhkiä ( pxMap.begin ( ) ); // poista ylä- ja alarivit kaikista sarakkeista, luo ensin työkaluja tätä varten: std :: vector < std :: vector < int > >:: iterator iterlvl2 ; // iteraattori toiselle ulottuvuudelle. std :: vektori < int >:: iteraattori iterlvl1 ; // ensimmäisen ulottuvuuden iteraattori // Siirry syvälle kohteelle ( iterlvl2 = pxMap . begin (); iterlvl2 != pxMap . end (); iterlvl2 ++ ) { iterlvl1 = ( * iterlvl2 ). alkaa (); // Vain esittelytarkoituksiin ( * iterlvl2 ). pop_back (); ( * iterlvl2 ). erase (( * iterlvl2 ) .begin ()); // Missä olemme? kokoY = ( * iterlvl2 ). koko (); // Aseta kokoY, kun olemme tällä tasolla. Silloin emme voi tehdä sitä } }Esimerkki yksiulotteisesta dynaamisesta vektorista, joka lajittelee ja poistaa kaksoiskappaleita:
#sisällytä <vektori> #sisällytä <merkkijono> #include <algoritmi> // Std::sort-, std::unique-algoritmien käyttäminen int main () { std :: vektori < std :: merkkijono > v_str ; //Tyhjä vektori v_str v_str . push_back ( "zz" ); // {"zz"} v_str . push_back ( "aa" ); // {"zz", "aa"} v_str . push_back ( "bb" ); // {"zz", "aa", "bb"} v_str . push_back ( "aa" ); // {"zz", "aa", "bb", "aa"} v_str . push_back ( "xx" ); // {"zz", "aa", "bb", "aa", "xx"} v_str . push_back ( "dd" ); // {"zz", "aa", "bb", "aa", "xx", "dd"} v_str . push_back ( "xx" ); // {"zz", "aa", "bb", "aa", "xx", "dd", "xx"} //Lajittele kaikki vektorin elementit std :: sort ( v_str . begin (), v_str . end ()); //Vektorilajittelun tulos: {"aa", "aa", "bb", "dd", "xx", "xx", "zz"} // Poista kaksoiskappaleet v_str . erase ( std :: ainutlaatuinen ( v_str . alkaa (), v_str . end () ), v_str . end () ); //Tulos kaksoiskappaleiden poistamisesta: {"aa","bb","dd","xx","zz"} return 0 ; }