You are on page 1of 8

The STL is a collection of containers that holds several elements of the same type.

Vector

A vector is an array whose size can be changed during the execution of the program. It supports operations such as removing
and inserting elements at any position in it.

To create a vector containing integers, we write:

vector<int> v;

This will create an empty vector that can store integers.

The function push_back() is used to append integers at the end in the vector, we write:

v.push_back(5); // vector becomes [5]


v.push_back(2); // vector becomes [5, 2]
v.push_back(3); // vector becomes [5, 2, 3]

The function back() returns the last element in the vector, and the function pop_back() removes the last element:

cout << v.back() << "\n"; // prints 3


v.pop_back(); // vector becomes [5, 2]
cout << v.back(); // prints 2

The elements can be accessed like an ordinary array, where v[i] refers to the i-th element in the vector.

Another way to create a vector is to give the number of elements and the initial value for each element:

vector<int> v1(5); //creates a vector containing 0, five times.


vector<int> v2(5, 3); //creates a vector containing 3, five times.

To create an array of 5 vectors, we write:

vector<int> v[5];

To create a multidimensional array i.e. vector of size N*M, we write:

vector<vector<int>> v(n, vector<int> (m,0));

The size() function returns the number of elements in the vector. Its data type is unsigned, which may sometimes cause
problems. You should typecase it to int like: (int)v.size().

There is an empty() function that checks if the vector is empty and a clear() function which makes the vector contain 0 elements.

The resize() function makes the vector contain the required number of elements. If fewer elements than the size of the vector
are required, the last ones will be deleted and if more elements are required, it will enlarge its size and fill the newly created
elements with zeroes.

The string is also a dynamic array that can be used almost like a vector.

To sort the vector, we write:


sort(v.begin(), v.end());

To sort the vector with conditions(here, in descending order), we use the comparator function:

bool comp(int x, int y) {


return x > y;
}
int main() {
vector<int> v;
//insert elements here
sort(v.begin(), v.end(), comp);
return 0;
}

An easier way to sort the vector in decreasing order would be:

sort(v.rbegin(), v.rend());

Or you can simply store the negative integers in the vector and sort them in ascending order.

Pairs

Pairs are used to store two values of different data types.

To create a pair containing integers and strings, we write:

pair<int, string> p;

To access the first and second element, we write:

p.first = 5;
p.second = "hello";

At a more complex level, it could be:

pair<string,pair<int,int>> p;

They are mostly used with other STL like vectors:

vector<pair<int, int>> v;
v.push_back(make_pair(4, 5));

A shorter way would be:

v.push_back({4, 5});

The great advantage of pairs is that they have built-in operations to compare themselves. When sorted, the result will be based
on the comparison of the first elements only; the second element will be compared only if the first ones are equal.

Iterators

In STL iterators are the most general way to access data in containers. An iterator is a variable that points to an element in a
data structure.
The STL uses two iterators, called begin() and end(). The begin() iterator points to the position of the first element in the data
structure and the end() iterator points to the position after the last element in the data structure.

The iterators begin() and end() are used to process all elements in a data structure.

sort(v.begin(), v.end());
sort(v.rbegin(), v.rend());

Iterators are often used to access elements of a set/map. The following iterator points to the first element of the set:

set<int>::iterator it = s.begin();
A shorter way would be:
auto it = s.begin();

The following iterator points to the last element:

set<int>::iterator it = s.begin();
it--;

Queue

A queue is a data structure, similar to a real-life queue which follows First In First Out(FIFO).

To create a queue containing integers, we write:

queue<int> q;

It supports two O(1) operations: push() - adding an element to the end of the queue, and pop() - removing the first element in
the queue:

q.push(2); // queue becomes [2]


q.push(7); // queue becomes [2, 7]
q.push(3); // queue becomes [2, 7, 3]
cout << q.front() << "\n"; // prints 2
q.pop(); // queue becomes [7, 3]
cout << q.front(); // prints 7

The size() function returns the number of elements in the queue. There is also an empty() function which checks if the queue is
empty. There is no clear() function, if you want to clear the queue, simply pop() all the elements.

Stack

A stack is a data structure, similar to a real-life stack which follows Last In First Out(LIFO).

To create a stack containing integers, we write:

stack<int> s;

It supports two O(1) operations: push() - adding an element to the top of the stack, and pop() - removing the element from the
top of stack:

s.push(2); // stack becomes [2]


s.push(7); // stack becomes [2, 7]
s.push(3); // stack becomes [2, 7, 3]
cout << s.top() << "\n"; // prints 3
s.pop(); // stack becomes [2, 7]
cout << s.top(); // prints 7

The size() function returns the number of elements in the stack. There is also an empty() function which checks if the stack is
empty. There is no clear() function, if you want to clear the stack, simply pop() all the elements.

String

Strings have a substring() function which does not use iterators. It is of the form:

s.substr(start, length);

Here, the start is the index from which you want to delete the string of given length.

string s = "apple";
string s1 = s.substr(0,3); //app
string s2 = s.substr(2); //ple

Deque

A deque is a dynamic array whose size can be efficiently changed at both ends of the array. They are called double ended
queues since a deque provides the functions push_back() and pop_front(), along with the functions push_front() and pop_back().

To create a deque containing integers, we write:

deque<int> d;

It supports four O(1) operations: push_front(), push_back(), pop_front(), pop_back() :

d.push_back(2); // deque becomes [2]


d.push_back(5); // deque becomes [2, 5]
d.push_front(1); // deque becomes [1, 2, 5]
for (int i:d) {
cout << i << " ";
}
cout << "\n";
d.pop_front(); // deque becomes [2, 5]
d.pop_back(); // deque becomes [2]

The size() function returns the number of elements in the deque. There is also an empty() function that checks if the deque is
empty.

The internal implementation of a deque is more complex than that of a vector, and for this reason, a deque is slower than a
vector

Set

A set is a data structure that maintains a collection of unique elements, similar to a mathematical set. The benefit of the set
structure is that it maintains the order of the elements. Unlike vectors, particular positions in the set can not be accessed using
the [ ] operator.

The structure set is based on a balanced binary tree and its operations work in O(logn) time.

To create a set containing integers, we write:


set<int> s;

It supports four O(logN) operations: insert(), erase() and count() and find():

s.insert(3); // set becomes [3]


s.insert(2); // set becomes [2, 3]
s.insert(3); // set becomes [2, 3]
s.insert(5); // set becomes [2, 3, 5]
cout << s.count(3) << "\n"; // prints 1
s.erase(3); // set becomes [2, 5]
if (s.find(5) == s.end()) { // this does not execute since 5 is present in the set
cout << "5 is not present in the set";
}

Since a set is not a linear container, it is not possible to take the elements in the set by index. We can traverse the elements of
the set using iterators.

for(set<int>::const_iterator it = s.begin(); it != s.end(); ++it) {


cout << *it << " ";
}

A simpler way to print the elements would be:

for (auto i : s) {
cout << i << " "; // this prints - 2 5
}

The C++ standard library contains another implementation of the set, unodered_set. As its name suggests, it does not maintain
the elements in order, but the elements are unique.

The structure unordered_set uses hashing, and its operations work in O(1) time on average, but it can go up to linear time O(n)
in the worst case which depends on the internally used hash function. There are few functions that are not present in an
unordered_set but it can be more efficient at times.

The size() function returns the number of elements in the set/unordered_set. There is an empty() function which checks if the
set/unordered_set is empty and a clear() function which makes the set/unordered_set contain 0 elements.

Map

A map is a data structure that is very similar to a set. It is a generalized count array that consists of key-value pairs. The keys and
values can be of any data type.

The structure map is based on a balanced binary tree and its operations work in O(logn) time.

To create a map where the keys are strings and the values are integers, we write:

map<string, int> m;

Accessing the value associated with a key is done using the operator [ ], for example, m[“apple”] would access the value
associated with the “apple” key.

It supports four O(logN) operations: insert(), erase() and count() and find():

m.insert({"apple", 1});
m["banana"] = 2; // this is more commonly used to insert a new key-value pair
cout << m["apple"] << "\n"; // prints 1
m["apple"]++;
cout << m["apple"] << "\n"; // prints 2
cout << m["grapes"] << "\n"; // prints 0, If the map does not contain the key,
// it is added to the map with a default value.
cout << m.count("banana") << "\n"; // prints 1
m.erase("apple");
cout << m.count("apple") << "\n"; // prints 0
if(m.find("grapes") != m.end()) { // this executes since grapes is present in the map
cout << "grapes is present in the map\n";
}

To print all the key-value pairs in a map:

for (auto i : m) {
cout << i.first << " " << i.second << "\n";
}

The C++ standard library contains another implementation of a map, unodered_map. As its name suggests, it does not maintain
the elements in order, but the elements are unique.

The structure unordered_map uses hashing, and its operations work in O(1) time on average, but it can go up to linear time O(n)
in the worst case which depends on the internally used hash function. There are few functions that are not present in an
unordered_map but it can be more efficient at times.

The size() function returns the number of elements in the map/unordered_map. There is an empty() function which checks if the
map/unordered_map is empty and a clear() function which makes the map/unordered_map contain 0 elements.

Multiset/Multimap

Multiset/multimap works the same way as set/map, except for the fact that it can store multiple instances of an element.

To create a set containing integers, we write:

multiset<int> s;

All operations are the same as set, except the erase() function. It removes all instances of an element. This can be shown as:

s.insert(4);
s.insert(4);
cout << s.count(4) << "\n"; // prints 2
s.erase(4);
cout << s.count(4) << "\n"; // prints 0

To avoid this, we use (V.IMP):

s.insert(4);
s.insert(4);
cout << s.count(4) << "\n"; // prints 2
s.erase(s.find(4));
cout << s.count(4) << "\n"; // prints 1

Similar to a set/map, there is unordered_multiset/unordered_multimap as well.

Priority Queue

Priority Queue is a data structure that maintains a set of elements.

A priority queue is usually implemented using a heap structure that is much simpler than a balanced binary tree used in an
ordered set.
To create a priority queue containing integers, we write:

priority_queue<int> q;

It supports 2 O(log(N)) operations, push() and pop() and an O(1) operation top():

q.push(2); // pq becomes [2]


q.push(3); // pq becomes [3, 2]
q.push(5); // pq becomes [5, 3, 2]
q.push(3); // pq becomes [5, 3, 3, 2]
cout << q.top() << "\n"; // prints 5
q.pop(); // pq becomes [3, 3, 2]
cout << q.top() << "\n"; // prints 3

The elements in a C++ priority queue are sorted in decreasing order, by default. If we want to create a priority queue that
supports finding and removing the smallest element, we can do it as follows:

priority_queue<int, vector<int>, greater<int>> q;

Bitset

A bitset is an array of bool whose each value is either 0 or 1.

Policy-based data structures

The g++ compiler also supports some data structures that are not part of the C++ standard library. These are called the Policy-
based Data Structures.

The following lines must be added to use them:

#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
We can define a data structure, indexed_set that is like a set but can be indexed like an array. It
is defined as:
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> indexed_set;

To create an indexed set containing integers, we write:

indexed_set s;

It supports the same operations as set, along with two new features - find_by_order() and order_of_key(). The first returns an
iterator to the k-th largest element and the second returns the number of items in a set that are strictly smaller than our item.

s.insert(2); // set becomes [2]


s.insert(5); // set becomes [2, 5]
s.insert(3); // set becomes [2, 3, 5]
cout << *s.find_by_order(2) << "\n"; // prints 5 since s[2] = 5
cout << s.order_of_key(3) << "\n"; // prints 1 since s[1] = 3

To use it like a multiset, you can define the tree as:

typedef tree<pair<int, int>, null_type, less<pair<int, int>, rb_tree_tag,


tree_order_statistics_node_update> indexed_set;

And store the elements as: {element, time}.


STL Algorithms and Functions

The STL provides three simple algorithms: min(a, b), max(a, b), and swap(a, b). min(a, b) and max(a, b) return the minimum
and a maximum number of the two and swap(a, b) swap the two elements.

If you are given three or more elements and you have to find the minimum/maximum element, you should use:

min({a, b, c, d});

The sort(begin, end) algorithm is used to sort an interval in ascending order. The find(begin, end, element) algorithm returns the
iterator where the given element first occurs, or end() if the element is not found. The count(begin, end, element) algorithm
returns the number of occurrences of the given element in an interval of the container.

Set and Map have member functions find() and count() which work in O(log N).

Another useful algorithm is next_permutation(begin, end). It makes the interval (begin, end) hold the next permutation of the
same elements, or returns false if the current permutation is the last one.

The function lower_bound(x) returns an iterator to the smallest element in the set whose value is at least x, and the function
upper_bound(x) returns an iterator to the smallest element in the set whose value is larger than x. In both functions, if such an
element does not exist, the return value ends ().

You might also like