Standard Template Library (STL)

Programming Workshop 2 (CSCI 1061U)

Faisal Qureshi

Faculty of Science, Ontario Tech University

http://vclab.science.uoit.ca


Standard Template Library

Sequential Containers

Sequential containers are class that can be used for storing other items

Examples

Allocating a vector of int

#include <vector>
std::vector<int> v;

Allocating a list of strings

#include <list>
#include <string>
std::list<std::string> s;

Allocating a deque of vectors of strings

#include <deque>
#include <vector>
#include <string> 
std::deque<std::vector<std::string> >

The space between the last two > in std::deque<std::vector<std::string> > is important.

Properties

Container Access Addition Deletion
vector O(1) End O(n)
list O(n) Anywhere O(1)
deque O(1) Both ends O(n)

Iterators

C++ STL containers (both sequential and associative) define “helper classes,” called iterators, to help iterate over each item in the container.

Example

#include <iostream>
#include <vector>

int main() 
{
    std::vector<int> v; 
    
    v.push_back(1); 
    v.push_back(2); 
    v.push_back(3);
    
    std::vector<int>::iterator i;
    for (i = v.begin(); i != v.end(); ++i) 
    {
        std::cout << *i << std::endl; 
    }
    return 0; 
}

An iterator variable has the same semantics as a pointer to the stored element. Dereference (use * operator) to get the actual value. Notice that we refer to the item as *i, since iterator i stores a pointer to an element in the container.

v.begin() points to the first element in the sequence. v.end() points to the last element in the sequence.

Reverse iterator

#include <iostream> 
#include <list> 

using namespace std;

int main() 
{
    list<string> names;
    names.push_back("john");
    names.push_back("amanda");

    list<string>::reverse_iterator i;
    for (i = names.rbegin(); i != names.rend(); ++i) 
    {
        cout << *i << endl;
    }
    return 0; 
}

Here names.rbegin() refers to the last element in the sequence. names.rend() refers to the first element of the sequence. ++i essentiall decrements the iterator.

Const and non-const iterators

std::vector<int>::iterator 
std::vector<int>::reverse_iterator 
std::vector<int>::const_iterator 
std::vector<int>::const_reverse_iterator

And the corresponding methods for initializing and checking iterators

std::set<T>

Associative Containers

Sequential containers provide no meaningful way to index the stored data. How do we index elements in vector? The elements are always indexed 0, 1, 2, …

Is it possible to index elements using labels, such as age["earth"] = 4530000000 or lastnames["John"].

STL provides std::map<K,V>, which is an associative container. Maps store (key,value) pairs. STL provides std::pair<K,V> for this purpose. std::map assumes that keys are unique, i.e., no two entries can have the same key.

std::map supports the following operations:

Iterators are available in std::map.

#include <map> 
#include <iostream> 
#include <string> 

using namespace std;

int main() 
{
    map<string, int> super_heros;
    super_heros["batman"] = 32;
    super_heros["wolverine"] = 137;
    super_heros["jean gray"] = 25;
    super_heros["superman"] = 35;

    map<string, int>::iterator i;
    for (i = super_heros.begin(); i != super_heros.end(); ++i) 
    {
        cout << "Age of " << i->first << " is " << i->second << endl;
    }

    return 0; 
}

Note that the items stores in std::map of type std::pair. Each pair stores a key and a pair.

std::pair<string, int> ages;
ages.first = "John"; // Key
ages.second = 10;    // Value

Maps are sometimes referred to as hashes or dictinaires. Each key type should have a < operator. This means that we can use a std::string as a key, but not a char array. Value type should have default constructor. Map provides [] operator for both insertion and retrieval.

Look up

Associative container std::map supports O(log n) look up using the find method as seen below.

#include <map> 
#include <iostream> 
#include <string> 

using namespace std;

int main() 
{
    map<string, int> super_heros;
    super_heros["batman"] = 32;
    super_heros["wolverine"] = 137;
    super_heros["jean gray"] = 25;
    super_heros["superman"] = 35;
  
    map<string, int>::iterator i = super_heros.find("batman"); 
    if (i != super_heros.end()) {
        cout << "Batman is " << i->second << endl;
    }
    return 0; 
}

find returns an iterative to the (key,value) pair if the key is found; otherwise, it returns an iterator equal to end().

Multimaps

STL also provides std::multimap<K,V> that allows elements with repeating keys.

Element Ordering

It is important to remember that elements have no particular ordering in maps or multimap. This also means that there isn’t an element 0.

Container Adapters

These are template classes that are built “on top of” other classes.

Atapter classes have default underlying containers. E.g., std::stack is implemented using std::deque. It is, however, possible to specify a different container as follows

std::stack<int, std::vector<int> >

Again, note the space between the last two >.

Algorithms

STL also implements a number of algorithms that strive to be optimally efficient. Broadly speaking, we can divide these algorithms into two classes: 1) non-modifying sequence and 2) modifying sequence algorithms.

Non-modifying sequence algorithms

These templated functions do not modify the contents of the container. An example is std::find(), which returns the iterator to the matching element or std::end() if none is found.

Modifying sequence algorithms

These templated funtions can change the contents of the container. Adding or removing elements may invalidate an iterator. std::list guarantees that no iterator will be changed; however, std::vector and std::deque provide no such guarantees.

c++11 Ranged for

Starting c++11 the following works:

ranged-for.cpp

#include <iostream>
#include <string>
#include <map>

using namespace std;

int main() 
{
    map<int, string> persons = ; 
    for (auto i : persons) {
     cout << "id = " << i.first << " name = " << i.second << endl;
    }
    return 0; 
}

You can compile this as follows:

> g++ -std=c++11 ranged-for.cpp

References