1. C++:n STL-kirjasto C-kielen ongelma on, että taulukkojen koot on tiedettävä etukäteen. Lisäksi C ei tarjoa mitään keinoa automaattiseen indeksin tarkistukseen. Toisin sanoen on täysin ohjelmoijan vastuulla, ettei taulukoa indeksoida sen koon yli. Sovelluksissa on usein tarpeen kasvattaa tai supistaa taulukon kokoa lennossa. Tämä on toki mahdollista ohjelmoida itsekin new ja delete-operaattoreilla. Ei kuitenkaan välttämättä kannata keksiä pyörää uudelleen, koska C++:n Standardimallikirjasto (Standard Template Library) eli STL sisältää suuren joukon valmiita tietorakenteita olioiden dynaamiseen käsittelyyn. Aikaisemmin tällä kurssilla on käytetty jo string-luokkaa, joka kuuluu STL-kirjastoon. Tässä yhteydessä tarkastellaan kahta muuta yksinkertaista STL:n avulla toteutettavaa tietorakennetta list, vector ja map. Täydellinen kuvaus STL:n luokista löytyy esimerkiksi Silicon Graphicsin kotisivuilta osoitteessa http://www.sgi.com/tech/stl/table_of_contents.html Käsitteitä Malli eli template on määrittely, jota käyttämällä voidaan luoda samankaltaisten olioiden perheitä. Malli on ohje kääntäjälle luoda geneerisestä tyyppiriippumattomasta ohjelmakoodista tyyppiin sidottua ohjelmakoodia. Malleja käytetään, kun samanlainen logiikka toistuu eri tietotyyppejä käytettäessä. Tarkemmin Malleista kerrotaan Markun materiaalissa luvussa 25. Esimerkkejä: Luodaan vektori luvut, joka sisältää kokonaislukuja: vector <int> luvut; Luodaan lista nimet, joka sisältää merkkijonoja: list <string> nimet; Kaikille vektori- ja listaoliolle on esimerkiksi olemassa metodi, joka lisää tai poistaa niihin uuden alkion riippumatta siitä, mikä alkion tyyppi on. Säiliö eli container on olio, joka sisältää toisia olioita. Säiliöllä on metodeja, joiden avulla se pystyy käsittelemään sisältämiään olioita. Jokaiselle säiliötyypille on määritelty iteraattori-tyyppi, jonka avulla säiliön alkiot käydään läpi. Säiliö omistaa sisältämänsä oliot ja olioiden elinaika ei voi olla pidempi kuin itse säiliön.
STL:n kaikki säiliöluokat: Yksinkertaiset säiliöluokat (Simple Container Classes) o vector o list o stack o queue o deque Assosiatiiviset säiliöluokat(associative Container Classes) o map o set o multimap o multiset Lähes kaikki säiliöluokat sisältävät seuraavat metodit: push_front Lisätään alkio säiliön alkuun (ei määritelty vektorille) pop_front Poistetaan ensimmäinen alkio (ei määritelty vektorille) push_back Lisätään alkio säiliön loppuun pop_back Poistetaan viimeinen alkio empty Totuusarvo joka ilmaisee onko säiliö tyhjä size Säiliön koko insert Lisätään uusi alkio erase Poistetaan alkio clear Poistetaan kaikki alkiot resize Muutetaan säiliön kokoa front Osoitin ensimmäiseen alkioon back Osoitin viimeiseen alkioon Iteraattori on yleistetty osoitin. Se osoittaa säiliön yksittäiseen elementtiin. Sen käsittely ohjelmassa on hyvin samankaltainen kuin osoittimen: Esimerkki: vector <int>::iterator it; it++; //siirretään iteraattori seuraavaan säiliön alkioon cout << *it; //tulostetaan it:n osoittaman alkion sisältö Vektori Vektori muistuttaa tavallista C-taulukkoa siinä, että se sisältää nolla tai useampia samantyyppistä ja kokoista alkiota, jotka sijaitsevat keskusmuistissa peräkkäisissä muistipaikoissa. Uusia alkioita voidaan lisätä ja poistaa vektorin lopusta. Alkioihin
voidaan viitata satunnaisessa järjestyksessä []-indeksoinnilla (kuten C:n taulukkoon). Periaatteessa on mahdollista lisätä alkioita myös vektorin alkuun tai keskelle, mutta linkitetty lista on niihin tapauksiin parempi ratkaisu. Vektori on STL:n säiliöluokista yksinkertaisin ja samalla yleensä kaikkein tehokkain. Tässä ohjelmassa luetaan lukuja vektoriin luvut niin kauan kunnes syötetään eipositiivinen kokonaisluku. Huomaa, että missään vaiheessa ohjelmoijan ei välttämättä tarvitse tietää vektorin kokoa eikä huolehtia siitä, onko tilaa riittävästi. Metodit begin() ja end()palauttavat osoittimen vektorin alkuun ja loppuun (viimeisen alkion jälkeen). #include <iostream> #include <vector> using namespace std; int main() vector <int> luvut; vector <int>::iterator it; //iteraattori int x; do cout << "Luku? " << endl; cin >> x; luvut.push_back(x); //Lisää alkio vektorin loppuun while (x>0); cout << "Vektorissa on " << luvut.size() << " alkiota." <<endl; for (it=luvut.begin();it!=luvut.end();it++) cout << *it << endl; return 0;
Oheisessa kuvassa on havainnollistettu push_back()- metodin toimintaa: Vektoriin lisätään 5. alkio, jonka arvo on 10. Osoitin vektorin loppuun luvut.end() siirtyy automaattisesti. Säiliö voi olla muukin kuin valmiiksi määritelty tietotyyppi. Seuraavassa on määritelty tietue rekisteri, joka sisältää opiskelijan etunimen, sukunimen ja arvosanan. Rekisteri-tyyppinen muuttuja nimi sisältää yhden opiskelijan tiedot. Vektori nimet sisältää listan kaikista opiskelijoista. #include <iostream> #include <vector> #include <string> using namespace std; struct rekisteri string en; string sn; int as; ; int main() rekisteri nimi; vector <rekisteri> nimet; vector <rekisteri>::iterator it; //iteraattori char x; do cout << "Etunimi? " << endl; cin >> nimi.en; cout << "Sukunimi? " << endl; cin >> nimi.sn; cout << "Arvosana? " << endl; cin >> nimi.as; nimet.push_back(nimi); fflush(stdin); cout << "Jatketaanko (k/e)?" << endl; cin.get(x);
while (x!='e'); cout << "Vektorissa on " << nimet.size() << " alkiota." <<endl; for (it=nimet.begin();it!=nimet.end();it++) cout << it -> en << " " << it ->sn << " " << it -> as << endl; return 0; Edelliseen vielä sellainen huomautus, että iteraattori on aina osoitin. Tässsä iteraattori it on osoitin tietueeseen. Tietueosoittimen yksittäiseen kenttään viitataan nuolioperaattorilla ->. Tässä luettelo vector-luokan metodeista: assign at back begin Erases a vector and copies the specified elements to the empty vector. Returns a reference to the element at a specified location in the vector. Returns a reference to the last element of the vector. Returns a random-access iterator to the first element in the container.
capacity clear empty end erase front get_allocator insert max_size pop_back push_back rbegin rend resize reserve size swap Returns the number of elements that the vector could contain without allocating more storage. Erases the elements of the vector. Tests if the vector container is empty. Returns a random-access iterator that points just beyond the end of the vector. Removes an element or a range of elements in a vector from specified positions. Returns a reference to the first element in a vector. Returns an object to the allocator class used by a vector. Inserts an element or a number of elements into the vector at a specified position. Returns the maximum length of the vector. Deletes the element at the end of the vector. Add an element to the end of the vector. Returns an iterator to the first element in a reversed vector. Returns an iterator to the end of a reversed vector. Specifies a new size for a vector. Reserves a minimum length of storage for a vector object. Returns the number of elements in the vector. Exchanges the elements of two vectors. Lista STL:n lista on ns. kaksoislinkitetty lista (double linked list).. Lista koostuu peräkkäisestä solmuista. Solmu sisältää datan sekä joko yksi tai kaksi linkkiä listan edelliseen ja / tai seuraavaan alkioon. Yksinkertainen linkitetty lista sisältää datan ja osoittimen seuraavaan listan alkioon: Kaksisuuntainen linkitetty lista sisältää osoittimen sekä edelliseen että seuraavaan alkioon: Kaksoislinkitetty lista tarvitsee enemmän tilaa keskusmuistista kuin yksinkertainen. Se tarjoaa kuitenkin vastaavasti monipuolisemman tavan käydä listaa läpi molempiin suuntiin.
Ohessa graafisesti esitettynä listan alkion lisääminen ja poisto. STL:n listaan voi lisätä alkioita joko alkuun (push_front), loppuun (push_back) tai välille (insert). #include <iostream> #include <list> using namespace std; int main() list <int> luvut1,luvut2; list <int>::iterator it; int luku; do cout << "Luku?" << endl; cin >> luku; //Pano edestä: luvut1.push_front(luku); //Pano takaa: luvut2.push_back(luku); while (luku>0); cout << "luvut1:" << endl;
for (it=luvut1.begin();it!=luvut1.end();it++) cout << *it << endl; cout << "luvut12:" << endl; for (it=luvut2.begin();it!=luvut2.end();it++) cout << *it << endl; return 0; Ohessa on esitetty luettelo list-luokan metodeista: assign back begin clear empty end erase front Erases elements from a list and copies a new set of elements to the target list. Returns a reference to the last element of a list. Returns an iterator addressing the first element in a list. Erases all the elements of a list. Tests if a list is empty. Returns an iterator that addresses the location succeeding the last element in a list. Removes an element or a range of elements in a list from specified positions. Returns a reference to the first element in a list. get_allocator Returns a copy of the allocator object used to construct a list. insert max_size merge pop_back pop_front push_back push_front rbegin remove remove_if rend resize reverse size Inserts an element or a number of elements or a range of elements into a list at a specified position. Returns the maximum length of a list. Removes the elements from the argument list, inserts them into the target list, and orders the new, combined set of elements in ascending order or in some other specified order. Deletes the element at the end of a list. Deletes the element at the beginning of a list. Adds an element to the end of a list. Adds an element to the beginning of a list. Returns an iterator addressing the first element in a reversed list. Erases elements in a list that match a specified value. Erases elements from the list for which a specified predicate is satisfied. Returns an iterator that addresses the location succeeding the last element in a reversed list. Specifies a new size for a list. Reverses the order in which the elements occur in a list. Returns the number of elements in a list.
sort splice swap unique Arranges the elements of a list in ascending order or with respect to some other order relation. Removes elements from the argument list and inserts them into the target list. Exchanges the elements of two lists. Removes adjacent duplicate elements or adjacent elements that satisfy some other binary predicate from the list. Map Map on säiliöluokka, jossa tieto esitetään avain-arvo-pareina. Avain ja arvo säilytetään oliossa, jonka tyyppi on pair. Luokalla pair on kaksi jäsentä: o o first on avain second on itse arvo Esimerkki: map<int, string *> PhoneBook; Muistissa oheinen map-määrittely näyttää seuraavalta:
Esimerkkiohjelma tulostaa teletappien nimet ja värit. Nimi on avain ja väri on data #include <iostream> #include <map> #include <string> using namespace std; int main() map<string, string> teletapit; teletapit["tiivitaavi"]="violetti"; teletapit["hipsu"]="vihreä"; teletapit["laalaa"]="keltainen"; teletapit["pai"]="punainen"; map<string, string>::const_iterator iter; for (iter=teletapit.begin();\ iter!= teletapit.end(); ++iter) cout << iter->first << " on väriltään " \ << iter->second << endl; return 0; Algoritmit STL-kirjastossa on joukko valmiita algoritmeja, joiden avulla monet tyypilliset ohjelmointitehtävät on mahdollista tehdä ilman, että niitä tarvitsee kirjoittaa itse alusta. Tällaisia toimintoja on esimerkiksi lajittelu (sort) ja haku (find). Olemme aikaisemmin
tutustuneet mm. swap- ja reverse-algoritmeihin. Tässä on esitetty täydellinen lista STL:n algoritmeista. Läheskään kaikkia ei tällä kurssilla tarvita, mutta lienee hyvä tietää, mitä kaikkea löytyy valmiina, jos jotain näistä joskus oikeasti tarvitsee. This section provides a list of all the standard STL algorithms listed by category, together with an encoded description of their input parameters and a brief synopsis. The following table shows the meanings of letters used to decode input parameters shown in the algorithm list. Key Meaning Key Meaning b Bi-directional iterator p Predicate f Forward iterator r Random access iterator g Function object v Value i Input iterator & Reference to a value o Output iterator For example, the input parameters for the for_each() algorithm are iig. Using the above table, you can determine that for_each() takes two input iterators and a function object as arguments. Applying for_each iig Apply a function to every item in a range. Bounding equal_range ffv Return the lower and upper bounds within a range. lower_bound ffv Return the lower bound within a range. upper_bound ffv Return the upper bound within a range. Comparing equal iii Check that two sequences match. lexicographical_compare iii Lexicographically compare two sequences. mismatch iii Search two sequences for a mismatched item. Copying copy copy_backward Counting count count_if Filling fill fill_n Filtering unique unique_copy Generating generate iio Copy a range of items to another area. bbb Copy a range of items backwards to another area. iiv Count items in a range matching a value. iip Count items in a range satisfying a predicate. ff Set every item in a range to a particular value. o Set n items to a particular value. ff Collapse all consecutive values in a sequence. iio Copy a sequence, collapsing consecutive values. ffg Fill a sequence using a generator function. generate_n og Generate a specified number of items. Heap make_heap rr Make a sequence into a heap.
pop_heap rr Pop the top value from a heap. push_heap rr Place the last element into a heap. sort_heap rr Sort a heap. Math Operations accumulate iiv Sum the values in a range. adjacent_difference iio Calculate the difference between adjacent pairs of values. inner_product iiiv Calculate the inner product of two sequences. partial_sum iio Fill a range with a running total. median vvv Calculate the median of three values. Merging inplace_merge bbb Merge two sorted lists in place into a single sorted list. merge iiiio Merge two sorted lists into a single sorted list. Min/Max min max min_element ii max_element ii Partitioning nth_element && Return the minimum of two items. && Return the maximum of two items. Return the minimum item within a range. Return the maximum item within a range. rrr Partition a range by its nth element. partition bbp Partition a range using a predicate. stable_partition bbp Partition a range using a predicate. Permuting next_permutation bb Change sequence to next lexicographic permutation. prev_permutation bb Change sequence to last lexicographic permutation. Removing remove ffv Remove all matching items from a sequence. remove_copy iiov Copy sequence, removing all matching items. remove_copy_if iiop Copy sequence, removing all that satisfy predicate. remove_if ffp Remove items satisfying predicate from a sequence. Replacing replace replace_copy replace_if ffvv Replace specified value in a sequence with another. iiovv Copy sequence replacing values satisfying predicate. ffpv Replace specified values satisfying a predicate. Reversing reverse bb Reverse the items in a sequence. reverse_copy bbo Create a reversed copy of a sequence. Rotating rotate fff Rotate a sequence by n positions. rotate_copy fffo Copy a sequence, rotating it by n positions Searching adjacent_find ii Locate consecutive sequence in a range. binary_search ffv Locate an item in a sorted sequence. find iiv Locate an item in a sequence. find_if iip Locate an item satisfying a predicate in a range. search ffff Locate one sequence within another. Set Operations includes iiii Search for one sequence in another sequence. set_difference iiiio Create set of elements in first sequence that are not in second.
set_intersection set_symmetric_difference set_union iiiio Create set of elements that are in both sequences. iiiio Create set of elements that are not in both sequences. iiiio Create set of elements that are in either sequence. Shuffling random_shuffle rr Randomize sequence using random shuffles. Sorting partial_sort rrr Sort the smallest n elements of a sequence. partial_sort_copy iirr Sort the smallest n elements of a sequence. sort rr Sort a sequence. stable_sort rr Sort a sequence. Swapping iter_swap ff Swap the values indicated by two iterators. swap && Swap two values. swap_ranges fff Swap two ranges of items. Transforming transform iiog Transform one sequence into another.