Show Lecture.STLContainers as a slide show.
CS253 STL Containers
Overview
- The most popular containers:
Attributes
Name | Order | Search | Insert | Append |
string, vector | no | O(n ) | O(n ) | O(1) |
deque | no | O(n ) | O(n ) | O(1) |
list, forward_list | no | O(n ) | O(1) | O(1) |
[multi]set | < | O(log n ) | O(log n ) | |
[multi]map | < | O(log n ) | O(log n ) | |
unordered_[multi]set | hashed | O(1) | O(1) | |
unordered_[multi]map | hashed | O(1) | O(1) | |
Popular methods
Universal container methods | Popular container methods |
default ctor | ctor(n) |
copy ctor | ctor(iter, iter) |
.operator= | .size() |
.empty() | .insert() / .erase() |
.max_size() | .find() / .count() |
.clear() | .front() / .back() |
.begin() / .end() | .rbegin() / .rend() |
.cbegin() / .cend() | .crbegin() / .crend() |
Popular types
Universal types | Popular types |
value_type | key_type |
iterator | reverse_iterator |
const_iterator | const_reverse_iterator |
size_type | |
string con = "The quick brown fox jumps over a lazy dog.";
cout << "size=" << con.size() << ' ';
for (auto c : con)
cout << c;
size=42 The quick brown fox jumps over a lazy dog.
- This displays a std::string.
- After this, the same code will be shown, but using different
containers.
- Sure, we could have just said
cout << con;
since we’re using
a std::string, but but that won’t work for other container types.
string s = "The quick brown fox jumps over a lazy dog.";
vector<char> con(s.begin(), s.end());
cout << "size=" << con.size() << ' ';
for (auto c : con)
cout << c;
size=42 The quick brown fox jumps over a lazy dog.
We can’t initialize a vector directly from a C-style string,
so we put it into a C++ string, and initialize the vector
from that, using the two-iterator constructor.
string s = "The quick brown fox jumps over a lazy dog.";
array<char, 42> con;
for (size_t i=0; i<s.size(); i++)
con[i] = s[i];
cout << "size=" << con.size() << ' ';
for (auto c : con)
cout << c;
size=42 The quick brown fox jumps over a lazy dog.
- A std::array is not a C array, but its size is fixed at
compile time.
- Its storage is all on the stack, with no dynamic memory
allocation, so it’s as efficient as a C array. It has
typical STL container methods such as
.size()
, .begin()
,
.end()
, etc.
- It lacks the two-iterator ctor, perhaps due to its fixed size.
string s = "The quick brown fox jumps over a lazy dog.";
list<char> con(s.begin(), s.end());
cout << "size=" << con.size() << ' ';
for (auto c : con)
cout << c;
size=42 The quick brown fox jumps over a lazy dog.
- A list is a doubly-linked list.
- Large storage overhead, but insertion is cheap, and you can easily go
forward & backward.
- Unlike a vector,
.push_back()
never causes reallocation.
- When you iterate over a list, you don’t get a node—those are
internal. You just get the value stored in the node.
string s = "The quick brown fox jumps over a lazy dog.";
forward_list<char> con(s.begin(), s.end());
for (auto c : con)
cout << c;
The quick brown fox jumps over a lazy dog.
- A forward_list (formerly
slist
) is a singly-linked list.
- It has storage overhead, but insertion is cheap, and you can
easily go forward.
- When you iterate over a forward_list, you don’t get a node—those are
internal. You just get the value stored in the node.
- There is no
forward_list::size()
. Perhaps this was to keep an
empty forward_list small, by not having a size_t to keep the size:
forward_list<string> fl;
cout << sizeof(fl);
8
string s = "The quick brown fox jumps over a lazy dog.";
deque<char> con(s.begin(), s.end());
cout << "size=" << con.size() << ' ';
for (auto c : con)
cout << c;
size=42 The quick brown fox jumps over a lazy dog.
- Pronounced like “deck”: 🃚 🂻 🂭 🃎 🃑
- A deque is a double-ended queue.
- It’s like a vector, but you can easily push or pop from the
front or the back.
string s = "The quick brown fox jumps over a lazy dog.";
set<char> con(s.begin(), s.end());
cout << "size=" << con.size() << ' ';
for (auto c : con)
cout << c;
size=28 .Tabcdefghijklmnopqrsuvwxyz
- Generally implemented as a binary tree. Hence, it is sorted, has
fairly large storage overhead, and has O(log n )
find/insertion/deletion times.
- It’s intrinsically, always, sorted. You don’t have to sort it.
When you
.insert()
something, it gets put into the right place
to preserve the sortyness.
- When you iterate over a set, you don’t get a node—those are
internal. You just get the value stored in the node.
string s = "The quick brown fox jumps over a lazy dog.";
multiset<char> con(s.begin(), s.end());
cout << "size=" << con.size() << ' ';
for (auto c : con)
cout << c;
size=42 .Taabcdeefghijklmnoooopqrrsuuvwxyz
A multiset is like a set, but allows copies.
string s = "The quick brown fox jumps over a lazy dog.";
unordered_set<char> con(s.begin(), s.end());
cout << "size=" << con.size() << ' ';
for (auto c : con)
cout << c;
size=28 gdyzlavspmjxfn.huerTqickbo w
- Formerly
hash_set
- A hash table implementation that acts like a set
(no duplicates allowed).
- When you iterate over a unordered_set, you don’t get a bucket—those
are internal. You just get the value stored in the bucket.
string s = "The quick brown fox jumps over a lazy dog.";
unordered_multiset<char> con(s.begin(), s.end());
cout << "size=" << con.size() << ' ';
for (auto c : con)
cout << c;
size=42 .gdyzlaaspmjxfnwoooorrbkciuuqv eehT
A unordered_multiset (formerly hash_multiset
), is a hash table
implementation like a multiset.
map example
map<string, double> gpa = {
{ "Logan", 3.998 },
{ "Russ", 4.20 },
{ "Elisa", 3.92 },
{ "Craig", 2.0 }
};
for (auto p : gpa)
cout << p.first << " has a GPA of " << p.second << '\n';
cout << "Logan’s GPA is: " << gpa["Logan"] << '\n';
Craig has a GPA of 2
Elisa has a GPA of 3.92
Logan has a GPA of 3.998
Russ has a GPA of 4.2
Logan’s GPA is: 3.998
- A
map<A,B>
is like a set<pair<const A,B>>
, ordered by A
.
- When you iterate over a map, you get a pair,
with public data members (😲)
.first
and .second
.