# STL

Programming Workshop 2 (CSCI 1061U)

Faculty of Science, UOIT

http://vclab.science.uoit.ca

# Standard Template Library

• Containers
• Sequential containers
• Associative containers
• Generic algorithms
• Iterators
• Reverse iterators
• Const and non-const (mutable) iterators

# Sequential Containers

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

• Dynamic array -- `std::vector<T>`
• Linked list -- `std::list<T>`
• Deque -- `std::deque<T>`

## 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

`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

• `begin()`
• `end()`
• `cbegin()`
• `cend()`
• `rbegin()`
• `rend()`
• `crbegin()`
• `crend()`

# `std::set<T>`

• Implements sets, each value can only occur once
• Efficient at testing membership O(log n). Use find() method.
• The value type must have `<` operator Iterator is available

# 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:

• insertion
• removal
• lookup

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.

These are template classes that are built "on top of" other classes.

• `std::stack`
• `std::queue`
• `std::priority_queue`

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``