You are on page 1of 18

C++ STL

Containers

Sequential Containers
pair
vector

Ordered Containers
map
multi_map
set
multi_set

Unordered Containers
unordered_set
unordered_map

Iterators

Algorithms

Functors
Containers:

● Sequential Containers - Elements are stored sequentially, the


first element entered is stored first, second entered is stored
next,... (iter++ can be done)
● Ordered Containers - Elements are stored in increasing order,
irrespective of the order in which they were entered. (iter++ can
be done)
● Unordered Containers - Elements are stored in some random order.
(iter++ can be done)

Pairs:

Used when we want to preserve a particular property of a value when we


apply some operation on it.

pair <int, string> p;


Vector:
vector <int> v; - has no elements
vector <int> v(5); - has 5 elements all 0
vector <int> v(5, 3); - has 5 elements all 3

----------------------------------------------------------------------
vector <int> v(5);
v.push_back(7);
// Here, 7 is the 6th element. v -> 0 0 0 0 0 7
----------------------------------------------------------------------

vector <int> v1;


vector <int> v2 = v1;
// Vectors can be directly copied, unlike arrays. If you do the same
for arrays, we get 2 pointers pointing to the same array. But here, 2
different vectors are created
// To create 2 references to same vector, do: vector <int> &v2 = v1;
When you are passing a vector to a function, it is passed by value,
not by reference. The changes made to the vector in the function don’t
reflect in the actual vector.

// Passed by value
void print (vector <int> v) {

}
// Passed by reference
void print (vector <int> &v) {

}
In the latter case, all changes made to v in the function reflect in
the actual vector too, since it was passed by reference.

vector <int> v[10] - Array of 10 vectors


vector <vector <int>> v - Vector of vectors

// Vector elements can be accessed by using v[i]

Taking input for a vector of vectors:

First take input of a single row in a temporary vector, then


push_back() this vector into the bigger vector.

Reference:
Nesting In Vectors: C++ STL For Beginners | Competitive Programming…
The below code also performs the same activity as above

Reference:
Nesting In Vectors: C++ STL For Beginners | Competitive Programming…
Vectors have indexing of elements (i.e., each element is given some
index). So, in vectors, we can access elements using random access.
But, some other Data Structures like Maps and Sets don’t have
indexing. Their elements can only be accessed using iterators and we
can traverse through the DS using iter++;

Maps:
Maps store <key, value> pairs. i.e., map is a collection of pairs.
They create a mapping from keys to pairs.

Maps and Unordered Maps:

Maps:

In maps, the elements are stored in increasing order of keys. Strings


are stored in lexicographically increasing order.
Elements can be inserted into maps using the [] or using the insert
method: (Either way, insertion takes log n time because pairs in
increasing order of keys, n is num of Ele present by the time of
insertion)
Printing the elements in the map:
Note that since each element in a map is a pair, we use (*it).first to
print the key and (*it).second to print the value.

Printing the elements using auto keyword:


Note that we are using auto &pr because if we used auto pr, it would
still be correct, but, a new variable pr is created (memory waste), if
we use &pr, it works just as an alias, so, memory is saved.

Note: T.C. of m[4] = “Vamsi”; is O(log n), don’t think it is just 1


because it is a simple assignment.
Even writing just m[6]; takes log n time.

Not only does insertion take log n time, even accessing takes log n
time in Maps.

The keys have to be unique, if a key is repeated like follows:


The previous value of m[5] is overridden with the new value of m[5]

Some Common Methods that work on almost all DS in STL:


.size()
.find()
.erase()
.begin()
.end()
.clear()

Use set and map only when you want to store in Ascending order of
elements. Otherwise, use unordered_set and unordered_map. Be aware
that unordered_set and unordered_map are quite dangerous to use, their
T.C. might not be O(1) if the test cases are designed in such a way
that after Hashing, same result comes for many elements.
Avoid using unordered_map and unordered_set as much as possible
(Especially in CP where people try to hack your solution)

maps and sets use Red and Black Trees (Balanced Trees) to store,
therefore, almost every operation takes O(log n) worst-case time.

unordered_map and unordered_set use Hash Tables to store elements, so,


almost all operations take O(1) average time.

unordered_map can be used only with the key being either a primitive
type or string, others can’t be used as key of unordered_map as their
Hash Value can’t be computed. In such cases we have to use maps,
because in maps we just compare elements and put it in a Tree DS.

Maps are generally used when we have to find the frequency of elements

Sets:
Sets are a collection of unique values. Main difference b/w maps and
sets is: maps are collections of pairs. sets are collections of unique
values, not pairs.

Sets and Unordered Sets:

sets store values in the same way as maps.


unordered_sets store values in the same way as unordered_maps.

Again, sets can have any data type, i.e., set <pair<int, vector<int>>>
is possible like maps. And at the same time, like unordered_maps, they
can’t store complex data types, and can only store primitive + string
data types. Only unordered_set <int>,...unorderd_set <string> are
correct.

In set, values are stored in increasing order.


Insertion in set takes log n time, like map.
In maps, we can access elements by using []. But, we can’t use it for
sets. s[0], s[1], s[2],... are all invalid.

To find an element in a set, use .find(){O(log n) time}. It returns an


iterator to that particular element if found, else, returns s.end().

If an element is inserted twice, then it is stored only once.

.erase(iter) erases the element at the iterator “iter”


.erase(ele) erases the element passed
// Erase method is overloaded

Again almost all time complexities in unordered_set are O(1) average


T.C.

Sets are usually used when we want to find the unique elements in a
given input.
Maps are usually used when we want to find the frequency of each
element of the input.

Use unordered_set when you only want to store unique elements and the
order of storing doesn’t matter.
Use set when you want to store elements in an increasing order.
Multi-Set:
Allow storing the same value multiple times. It has the internal
implementation of set (i.e., using Red and Black Trees {Self-Balanced
Trees}). Since again Red and Black Trees are being used, the T.C. of
most operations is O(log n).

When we use .find (ele) method with multiset, the iterator of the
first occurrence of the element ele is returned.

When we use .erase (ele) {Second version of the overloaded method},


then all the occurrences of ele are deleted.

Stack:

We can create a stack of any data type (int, float, string, box,..)
Queues:

Iterators:
// iterator object to a vector declaration:
vector <int> :: iterator it;
// It’s initialization:
it = v.begin();
// To know value at iterator:
cout << *it;

// Difference b/w it++ and it+1


it++ makes it move to the next iterator
it+1 moves the iterator to the next location

● In case of vectors, because in arrays, the memory is contiguous,


and therefore the next iterator is in the next location itself,
both it++ and it+1 give the same result.
● However, in case of non-contiguous memory allocated DS like Maps,
Sets,... Doing it++ would go to the next element, but doing it+1
is invalid since it takes us to the immediate next memory
location which might or might not be the memory of the next
element.

Above is an example of a vector of pairs of integers and how to use


it.

Another alternative:

Range Based Loops:

An alternative to using for loop with iterators.

vector <int> vec = {8,9,1,0,1,5,1};


for (int i : vec) {
cout << i << endl;
}
// Note that ‘i’ above is a copy of the vector element
// The same Range Based Loop (for each loop) can be used on other DS
like Maps, Sets,...
// If you want the ‘i’ to be changing the actual value of the element
too, then use:

for (int &i : vec) {


cout << i << endl;
}
// Now, any change made to ‘i’ will reflect in vec

The above code snippet shows how to use for-each / range based loops
for vector of pairs.

Shorter Way to Declare Iterators:


Using the auto keyword.
auto - dynamically determines the data type of the value assigned to
it.
auto i = 2; (i is decided to be an int)
auto i = 2.0; (i is decided to be an double)

In the below case, it is determined to be an iterator of a vector.

In the below case ‘value’ is a variable of data type = pair <int, int>
Algorithms:
Sorting:
Inbuilt sorting algorithm exist. Using which we can sort arrays,
vectors,...
We can also create our own sorting algorithm using comparator function
(That is the criteria on basis of which we need the sorting can be
specified in the comparator function and sorting is done on that
basis)

Inbuilt sort:

sort (start_address, end_address+1);


Start address - from where you want to start sorting
End address - till where you want to do the sorting

int A[n];
sort(A, A+n);
// sort () uses intro sort - which is a mixture of quick sort, heap
sort and insertion sort.

Using sort() with vectors:


Using Comparator Function for Custom Sort:

bool cmp () {
// Body of comparator function
}

sort (v.begin(), v.end(), cmp); // sorts as per the cmp function

reverse() function:

Generally used with vectors and strings.

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


reverse (s.begin)

CP Notes:
CC Websites have a limitation on the amount of continuous memory that
can be allocated.
Max. size of array declared locally = 10^5
Max. size of array declared globally = 10^7
These same limits apply to vectors too as these are not limitations of
the arrays, but they are limitations of continuous memory allocation

Important Results
Useful for CP:
lcm (a,b) = a*b/(gcd(a,b))
Use __gcd (a,b) and lcm (a,b) in C++ for inbuilt implementations.

You might also like