Dynamic Arrays

An array whose size can be changed automatically during runtime.

vector<int> vec;
vec.push_back(5);
vec.push_back(7);
vec.push_back(9);
vec.push_back(11);
 
cout << vec[0] << endl;
cout << vec[1] << endl;
 
// normal for loop
for(int i = 0; i < vec.size(); i++) {
    cout << vec[i] << endl;
}
 
//range based loop
for(const int& i : vec) {
    cout << i << endl;
}
 
 
cout << vec.back() << endl; // 11
vec.pop_back();
cout << vec.back() << endl; // 9
 
//size 10, initial value = 0
vector<int> vec(10);
 
//size 10, initial value = 5
vector<int> vec(10, 5);

Strings

A dynamic arrays like vector but only contains chars.

string a = "abcde";
string b = a + a;
cout << b << endl; // abcdeabcde
b[0] = 'd';
cout << b << endl; // dbcdeabcde
string c = substr(3, 4);
cout << c << endl; // deab

Set

Maintains a collection of elements just like vector but has no duplicates.

C++ has two set implementations:

  • set - based on a binary tree and its operations work in O(logN) time.
  • unordered_set - uses hashing and its operation take O(1) on average.
set<int> s;
s.insert(3);
s.insert(2);
s.insert(5);
 
cout << s.count(3) << endl; // 1
cout << s.count(4) << endl; // 0
 
s.erase(3);
s.insert(4);
cout << s.count(3) << endl; // 0
cout << s.count(4) << endl; // 1

a set can be used like a vector but cant use the indexes to get the values.

set<int> s = {2, 5, 6, 8};
cout << s.size() << endl; // 4
 
for(const int& i : s) {
    cout << i << endl;
}

c++ also contains multiset and unordered_multiset that otherwise work like set and unordered_set but they can contain multiple instances of an element.

multiset<int> m;
m.insert(5);
m.insert(5);
m.insert(5);
cout << m.count(5) << endl; // 5
 
m.erase(5);
cout << m.count(5) << endl; // 0
 
//if want to remove only one instance 
s.erase(s.find(5));
cout << m.count(5) << endl; // 2

Map

A generalized array of key-value pairs. The structure map is based on balanced binary tree and accessing element takes O(logN) time, while the unordered_map uses hashing and accessing elements take O(1) time.

map<string, int> m;
m['monkey'] = 4;
m['banana'] = 3;
m['harpsichord'] = 9;
cout << m['banana'] << endl; // 3
 
for(const auto& i: m) {
    cout << i.first << " " << i.second << endl;
}

if the key-value pair are not present in the map but they are requested, the key-value pair is put into the map with value = 0;

cout << m['hi'] << endl;

To check if a key exists in a map:

if(m.count("hi")) {
    // key exists
}

Bitset

An array whose value is either 0 or 1.

bitset<10> s;
 
s[1] = 1;
s[3] = 1;
s[4] = 1;
 
cout << s[4] << endl; // 1
cout << s[5] << endl; // 0
 
bitset<10> s(string("0010011010"));
cout << s[4] << endl; // 1
cout << s[5] << endl; // 0

they are good cause we can to bitwise operations on them.

bitset<10> a(string("0010110110"))
bitset<10> b(string("1011011000"))
 
cout << (a & b) << endl;
cout << (a | b) << endl;
cout << (a ^ b) << endl;

Deque

A queue like data structure where we can insert and pop from both ends.

deque<int> d;
d.push_back(5);
d.push_back(2);
d.push_front(3);
 
d.pop_back();
d.pop_front();

deque is slower than a vector but still pushing and popping are O(1) operations.

Stack

A LIFO data structure that has two O(1) operations: pushing on top of stack and popping of the stack.

stack<int> s;
s.push(3);
s.push(2);
s.push(5);
 
cout << s.top() << endl;
s.pop();
cout << s.top() << endl;

Queue

A FIFO based data structure which also has two O(1) operations: pushing at end of queue and popping from front of queue.

queue<int> q;
q.push(3);
q.push(2);
q.push(5);
 
cout << q.front() << endl; // 3
q.pop();
cout << q.front() << endl; // 2

Priority queue

A heap based data structure.

priority_queue<int> q; // max heap
q.push(3);
q.push(5);
q.push(7);
q.push(2);
 
cout << q.top() << endl; // 7
q.pop();
q.push(6);
cout << q.top() << endl; // 6
 
priority_queue<int, vector<int> , greater<int>> q; // min heap

Policy based data structures

g++ also contains some data structures that are not part of c++ std library.

#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
 
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> indexed_set;
indexed_set s;
s.insert(2);
s.insert(3);
s.insert(7);
s.insert(9);
 
auto x = s.find_by_order(2);
cout << *x << "\n"; // 7
cout << s.order_of_key(7) << "\n"; // 2

If the element does not appear in the set, we get the position that the element would have in the set

cout << s.order_of_key(6) << "\n"; // 2
cout << s.order_of_key(8) << "\n"; // 3

both work in logarithmic time.