STL Containers

STL Containers

1. What is STL?

STL (Standard Template Library) is the core of the C++ standard library, providing data structures and algorithms.

STL Components

Component Description
Containers Data structures for storing data
Iterators Traversing container elements
Algorithms General-purpose functions like sorting, searching
Function Objects Objects that behave like functions

2. vector

A dynamic-sized array. Most commonly used.

Basic Usage

#include <iostream>
#include <vector>

int main() {
    // Creation
    std::vector<int> v1;                  // Empty vector
    std::vector<int> v2(5);               // Size 5, initialized to 0
    std::vector<int> v3(5, 10);           // Size 5, initialized to 10
    std::vector<int> v4 = {1, 2, 3, 4, 5}; // Initializer list

    // Adding elements
    v1.push_back(10);
    v1.push_back(20);
    v1.push_back(30);

    // Output
    for (int num : v1) {
        std::cout << num << " ";
    }
    std::cout << std::endl;  // 10 20 30

    return 0;
}

Element Access

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {10, 20, 30, 40, 50};

    // Index access
    std::cout << v[0] << std::endl;      // 10
    std::cout << v.at(2) << std::endl;   // 30 (range checked)

    // First/last
    std::cout << v.front() << std::endl;  // 10
    std::cout << v.back() << std::endl;   // 50

    // Size
    std::cout << "Size: " << v.size() << std::endl;
    std::cout << "Empty: " << v.empty() << std::endl;

    return 0;
}

Insertion and Deletion

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // Add/remove at end
    v.push_back(6);   // {1, 2, 3, 4, 5, 6}
    v.pop_back();     // {1, 2, 3, 4, 5}

    // Insert in middle
    v.insert(v.begin() + 2, 100);  // {1, 2, 100, 3, 4, 5}

    // Delete in middle
    v.erase(v.begin() + 2);  // {1, 2, 3, 4, 5}

    // Range deletion
    v.erase(v.begin(), v.begin() + 2);  // {3, 4, 5}

    // Clear all
    v.clear();

    return 0;
}

Iterators

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // Iterate with iterator
    for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // Using auto (recommended)
    for (auto it = v.begin(); it != v.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // Reverse iterator
    for (auto it = v.rbegin(); it != v.rend(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;  // 5 4 3 2 1

    return 0;
}

3. array

A fixed-size array.

#include <iostream>
#include <array>

int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};

    // Access
    std::cout << arr[0] << std::endl;
    std::cout << arr.at(2) << std::endl;
    std::cout << arr.front() << std::endl;
    std::cout << arr.back() << std::endl;

    // Size
    std::cout << "Size: " << arr.size() << std::endl;

    // Iterate
    for (int num : arr) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // Fill
    arr.fill(0);

    return 0;
}

4. deque

A container with fast insertion/deletion at both ends.

#include <iostream>
#include <deque>

int main() {
    std::deque<int> dq;

    // Add to front/back
    dq.push_back(1);
    dq.push_back(2);
    dq.push_front(0);
    dq.push_front(-1);

    // {-1, 0, 1, 2}
    for (int num : dq) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // Remove from front/back
    dq.pop_front();
    dq.pop_back();

    // {0, 1}
    for (int num : dq) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

5. list

A doubly-linked list.

#include <iostream>
#include <list>

int main() {
    std::list<int> lst = {3, 1, 4, 1, 5};

    // Add to front/back
    lst.push_front(0);
    lst.push_back(9);

    // Sort (member method)
    lst.sort();

    for (int num : lst) {
        std::cout << num << " ";
    }
    std::cout << std::endl;  // 0 1 1 3 4 5 9

    // Remove duplicates (consecutive only)
    lst.unique();

    for (int num : lst) {
        std::cout << num << " ";
    }
    std::cout << std::endl;  // 0 1 3 4 5 9

    // Insert
    auto it = lst.begin();
    std::advance(it, 2);  // Move 2 positions
    lst.insert(it, 100);  // Insert at that position

    return 0;
}

6. set

A sorted collection of unique elements.

#include <iostream>
#include <set>

int main() {
    std::set<int> s;

    // Insert
    s.insert(30);
    s.insert(10);
    s.insert(20);
    s.insert(10);  // Duplicate, ignored

    // Auto-sorted
    for (int num : s) {
        std::cout << num << " ";
    }
    std::cout << std::endl;  // 10 20 30

    // Size
    std::cout << "Size: " << s.size() << std::endl;  // 3

    // Search
    if (s.find(20) != s.end()) {
        std::cout << "20 found" << std::endl;
    }

    // count (0 or 1)
    std::cout << "Count of 30: " << s.count(30) << std::endl;

    // Delete
    s.erase(20);

    return 0;
}

multiset

A set that allows duplicates.

#include <iostream>
#include <set>

int main() {
    std::multiset<int> ms;

    ms.insert(10);
    ms.insert(10);
    ms.insert(20);
    ms.insert(10);

    for (int num : ms) {
        std::cout << num << " ";
    }
    std::cout << std::endl;  // 10 10 10 20

    std::cout << "Count of 10: " << ms.count(10) << std::endl;  // 3

    return 0;
}

7. map

A sorted container of key-value pairs.

#include <iostream>
#include <map>
#include <string>

int main() {
    std::map<std::string, int> ages;

    // Insert
    ages["Alice"] = 25;
    ages["Bob"] = 30;
    ages.insert({"Charlie", 35});
    ages.insert(std::make_pair("David", 40));

    // Access
    std::cout << "Alice: " << ages["Alice"] << std::endl;

    // Iterate (sorted by key)
    for (const auto& pair : ages) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    // Structured binding (C++17)
    for (const auto& [name, age] : ages) {
        std::cout << name << ": " << age << std::endl;
    }

    // Search
    if (ages.find("Alice") != ages.end()) {
        std::cout << "Alice found" << std::endl;
    }

    // Delete
    ages.erase("Bob");

    return 0;
}

Note: operator[]

std::map<std::string, int> m;

// Accessing non-existent key → inserts with default value (0)!
std::cout << m["unknown"] << std::endl;  // 0 (and gets inserted)
std::cout << m.size() << std::endl;      // 1

// Safe access
if (m.count("key") > 0) {
    std::cout << m["key"] << std::endl;
}

// Or use find
auto it = m.find("key");
if (it != m.end()) {
    std::cout << it->second << std::endl;
}

8. unordered_set / unordered_map

Hash table-based containers with average O(1) access.

unordered_set

#include <iostream>
#include <unordered_set>

int main() {
    std::unordered_set<int> us;

    us.insert(30);
    us.insert(10);
    us.insert(20);

    // Order not guaranteed
    for (int num : us) {
        std::cout << num << " ";
    }
    std::cout << std::endl;  // Order undefined

    // Search (O(1) average)
    if (us.count(20)) {
        std::cout << "20 found" << std::endl;
    }

    return 0;
}

unordered_map

#include <iostream>
#include <unordered_map>
#include <string>

int main() {
    std::unordered_map<std::string, int> umap;

    umap["apple"] = 100;
    umap["banana"] = 200;
    umap["cherry"] = 300;

    // Access (O(1) average)
    std::cout << "apple: " << umap["apple"] << std::endl;

    // Iterate (order undefined)
    for (const auto& [key, value] : umap) {
        std::cout << key << ": " << value << std::endl;
    }

    return 0;
}

set vs unordered_set

Feature set unordered_set
Internal structure Red-black tree Hash table
Sorted Yes No
Insert/search O(log n) O(1) average
Iteration order Sorted Undefined

9. stack and queue

Container adapters.

stack (LIFO)

#include <iostream>
#include <stack>

int main() {
    std::stack<int> s;

    // push
    s.push(10);
    s.push(20);
    s.push(30);

    // pop (LIFO)
    while (!s.empty()) {
        std::cout << s.top() << " ";  // Top element
        s.pop();
    }
    std::cout << std::endl;  // 30 20 10

    return 0;
}

queue (FIFO)

#include <iostream>
#include <queue>

int main() {
    std::queue<int> q;

    // push
    q.push(10);
    q.push(20);
    q.push(30);

    // pop (FIFO)
    while (!q.empty()) {
        std::cout << q.front() << " ";  // Front element
        q.pop();
    }
    std::cout << std::endl;  // 10 20 30

    return 0;
}

priority_queue

#include <iostream>
#include <queue>

int main() {
    // Default: max heap (larger values first)
    std::priority_queue<int> pq;

    pq.push(30);
    pq.push(10);
    pq.push(20);

    while (!pq.empty()) {
        std::cout << pq.top() << " ";
        pq.pop();
    }
    std::cout << std::endl;  // 30 20 10

    // Min heap
    std::priority_queue<int, std::vector<int>, std::greater<int>> minPq;

    minPq.push(30);
    minPq.push(10);
    minPq.push(20);

    while (!minPq.empty()) {
        std::cout << minPq.top() << " ";
        minPq.pop();
    }
    std::cout << std::endl;  // 10 20 30

    return 0;
}

10. pair and tuple

pair

#include <iostream>
#include <utility>

int main() {
    // Creation
    std::pair<std::string, int> p1("Alice", 25);
    auto p2 = std::make_pair("Bob", 30);

    // Access
    std::cout << p1.first << ": " << p1.second << std::endl;

    // Comparison
    if (p1 < p2) {  // Compares first, then second
        std::cout << p1.first << " < " << p2.first << std::endl;
    }

    return 0;
}

tuple

#include <iostream>
#include <tuple>
#include <string>

int main() {
    // Creation
    std::tuple<std::string, int, double> t("Alice", 25, 165.5);

    // Access
    std::cout << std::get<0>(t) << std::endl;  // Alice
    std::cout << std::get<1>(t) << std::endl;  // 25
    std::cout << std::get<2>(t) << std::endl;  // 165.5

    // Structured binding (C++17)
    auto [name, age, height] = t;
    std::cout << name << ", " << age << ", " << height << std::endl;

    return 0;
}

11. Container Selection Guide

Requirement Recommended Container
Sequential access + end insertion/deletion vector
Both ends insertion/deletion deque
Frequent middle insertion/deletion list
Unique elements + sorted set
Unique elements + fast search unordered_set
Key-value + sorted map
Key-value + fast search unordered_map
LIFO stack
FIFO queue
Priority priority_queue

12. Summary

Container Characteristics
vector Dynamic array, O(1) at end
array Fixed array
deque O(1) at both ends
list Doubly-linked list
set Sorted + unique
map Key-value + sorted
unordered_set Hash + unique
unordered_map Hash + key-value
stack LIFO
queue FIFO
priority_queue Heap

Next Steps

Let's learn about STL algorithms in 11_STL_Algorithms_Iterators.md!

to navigate between lessons