Programming Workshop 2 (CSCI 1061U)
Faculty of Science, Ontario Tech University
Sequential containers are class that can be used for storing other items
std::vector<T>std::list<T>std::deque<T>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.
| Container | Access | Addition | Deletion |
|---|---|---|---|
vector |
O(1) | End | O(n) |
list |
O(n) | Anywhere | O(1) |
deque |
O(1) | Both ends | O(n) |
C++ STL containers (both sequential and associative) define “helper classes,” called iterators, to help iterate over each item in the container.
#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.
#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.
std::vector<int>::iterator
std::vector<int>::reverse_iterator
std::vector<int>::const_iterator
std::vector<int>::const_reverse_iteratorAnd the corresponding methods for initializing and checking iterators
begin()end()cbegin()cend()rbegin()rend()crbegin()crend()std::set<T>< operator Iterator is
availableSequential 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; // ValueMaps 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.
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().
STL also provides std::multimap<K,V> that allows
elements with repeating keys.
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::stackstd::queuestd::priority_queueAtapter 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 >.
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.
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.
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.
forStarting 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