Home C++ Standard Template Library (STL) Containers tutorial

Standard Template Library (STL) Containers tutorial

The C++ Standard Template Library (STL) Containers provide a variety of data structures to store and manage data.

STL containers are divided into three main types:

  1. Sequence Containers: Store data in a linear fashion, including vector, deque, list.
  2. Associative Containers: Use keys to store elements in sorted order, such as set, map, multiset, and multimap.
  3. Container Adaptors: Provide specific ways to manage data access with stack-like and queue-like structures, such as stack, queue, and priority_queue.

Let’s explore each type of container with examples.

1. Sequence Containers: vector

A vector is a dynamic array that allows random access to elements, automatic resizing, and efficient push/pop operations at the end.

Example: Basic Operations with vector

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> numbers = {1, 2, 3};

    // Adding elements
    numbers.push_back(4);
    numbers.push_back(5);

    // Accessing elements
    cout << "Elements: ";
    for (int num : numbers) {
        cout << num << " ";
    }
    cout << endl;

    // Removing the last element
    numbers.pop_back();

    cout << "After pop_back: ";
    for (int num : numbers) {
        cout << num << " ";
    }
    cout << endl;

    return 0;
}

Output:

Elements: 1 2 3 4 5 
After pop_back: 1 2 3 4

2. Sequence Containers: deque

A deque (double-ended queue) allows efficient insertion and deletion at both the beginning and the end. It is useful for applications that require fast access to both ends of a sequence.

Example: Basic Operations with deque

#include <iostream>
#include <deque>
using namespace std;

int main() {
    deque<int> d = {2, 4, 6};

    // Adding elements at both ends
    d.push_front(1);
    d.push_back(7);

    // Accessing elements
    cout << "Elements: ";
    for (int x : d) {
        cout << x << " ";
    }
    cout << endl;

    // Removing elements from both ends
    d.pop_front();
    d.pop_back();

    cout << "After pop_front and pop_back: ";
    for (int x : d) {
        cout << x << " ";
    }
    cout << endl;

    return 0;
}

Output:

Elements: 1 2 4 6 7 
After pop_front and pop_back: 2 4 6

3. Sequence Containers: list

A list is a doubly linked list that allows efficient insertion and deletion of elements at any position. It does not support random access like vector and deque.

Example: Basic Operations with list

#include <iostream>
#include <list>
using namespace std;

int main() {
    list<int> numbers = {1, 2, 3};

    // Adding elements at front and back
    numbers.push_front(0);
    numbers.push_back(4);

    // Accessing elements
    cout << "Elements: ";
    for (int num : numbers) {
        cout << num << " ";
    }
    cout << endl;

    // Removing elements from front and back
    numbers.pop_front();
    numbers.pop_back();

    cout << "After pop_front and pop_back: ";
    for (int num : numbers) {
        cout << num << " ";
    }
    cout << endl;

    return 0;
}

Output:

Elements: 0 1 2 3 4 
After pop_front and pop_back: 1 2 3

4. Associative Containers: set

A set stores unique elements in a sorted order. Inserting, deleting, and finding elements are fast with a set.

Example: Basic Operations with set

#include <iostream>
#include <set>
using namespace std;

int main() {
    set<int> s = {3, 1, 4, 2, 5};

    // Adding elements
    s.insert(6);

    // Displaying elements (sorted automatically)
    cout << "Elements: ";
    for (int x : s) {
        cout << x << " ";
    }
    cout << endl;

    // Removing an element
    s.erase(4);

    cout << "After erase(4): ";
    for (int x : s) {
        cout << x << " ";
    }
    cout << endl;

    return 0;
}

Output:

Elements: 1 2 3 4 5 6 
After erase(4): 1 2 3 5 6

5. Associative Containers: map

A map is a container that stores key-value pairs with unique keys in a sorted order. It allows efficient access to values based on their keys.

Example: Basic Operations with map

#include <iostream>
#include <map>
using namespace std;

int main() {
    map<string, int> age;

    // Inserting key-value pairs
    age["Alice"] = 25;
    age["Bob"] = 30;
    age["Charlie"] = 28;

    // Accessing elements
    cout << "Bob's age: " << age["Bob"] << endl;

    // Iterating through map
    cout << "All ages:" << endl;
    for (const auto& pair : age) {
        cout << pair.first << " is " << pair.second << " years old." << endl;
    }

    return 0;
}

Output:

Bob's age: 30
All ages:
Alice is 25 years old.
Bob is 30 years old.
Charlie is 28 years old.

6. Associative Containers: multiset

A multiset stores elements in sorted order and allows multiple occurrences of the same value.

Example: Basic Operations with multiset

#include <iostream>
#include <set>
using namespace std;

int main() {
    multiset<int> ms = {1, 2, 2, 3, 3, 3};

    // Inserting elements
    ms.insert(4);
    ms.insert(4);

    // Displaying elements (sorted order, with duplicates)
    cout << "Elements: ";
    for (int x : ms) {
        cout << x << " ";
    }
    cout << endl;

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

    return 0;
}

Output:

Elements: 1 2 2 3 3 3 4 4 
Count of 3: 3

7. Container Adaptors: stack

A stack is a container adaptor that follows the Last-In-First-Out (LIFO) principle. It allows only push and pop operations from the top.

Example: Basic Operations with stack

#include <iostream>
#include <stack>
using namespace std;

int main() {
    stack<int> s;

    // Pushing elements onto the stack
    s.push(1);
    s.push(2);
    s.push(3);

    cout << "Top element: " << s.top() << endl;

    // Popping elements from the stack
    s.pop();
    cout << "After pop, top element: " << s.top() << endl;

    return 0;
}

Output:

Top element: 3
After pop, top element: 2

8. Container Adaptors: queue

A queue is a container adaptor that follows the First-In-First-Out (FIFO) principle. Elements can be added at the back and removed from the front.

Example: Basic Operations with queue

#include <iostream>
#include <queue>
using namespace std;

int main() {
    queue<int> q;

    // Adding elements to the queue
    q.push(1);
    q.push(2);
    q.push(3);

    cout << "Front element: " << q.front() << endl;

    // Removing elements from the queue
    q.pop();
    cout << "After pop, front element: " << q.front() << endl;

    return 0;
}

Output:

Front element: 1
After pop, front element: 2

9. Container Adaptors: priority_queue

A priority_queue is a container adaptor that operates as a max-heap by default, where the largest element has the highest priority.

Example: Basic Operations with priority_queue

#include <iostream>
#include <queue>
using namespace std;

int main() {
    priority_queue<int> pq;

    // Adding elements to the priority queue
    pq.push(10);
    pq.push(30);
    pq.push(20);

    cout << "Top element: " << pq.top() << endl;

    // Removing elements from the priority queue
    pq.pop();
    cout << "After pop, top element

: " << pq.top() << endl;

    return 0;
}

Output:

Top element: 30
After pop, top element: 20

10. Associative Containers: unordered_map

An unordered_map is similar to a map but does not sort elements, allowing faster access times by using a hash table.

Example: Basic Operations with unordered_map

#include <iostream>
#include <unordered_map>
using namespace std;

int main() {
    unordered_map<string, int> ages;

    // Inserting key-value pairs
    ages["Alice"] = 25;
    ages["Bob"] = 30;
    ages["Charlie"] = 28;

    // Accessing elements
    cout << "Alice's age: " << ages["Alice"] << endl;

    // Iterating through unordered_map
    cout << "All ages:" << endl;
    for (const auto& pair : ages) {
        cout << pair.first << " is " << pair.second << " years old." << endl;
    }

    return 0;
}

Output:

Alice's age: 25
All ages:
Alice is 25 years old.
Bob is 30 years old.
Charlie is 28 years old.

Summary Table of STL Containers

Container Type Container Description
Sequence Container vector Dynamic array with random access
Sequence Container deque Double-ended queue, fast insertion/deletion at both ends
Sequence Container list Doubly linked list, fast insertion/deletion at any position
Associative Container set Stores unique, sorted elements
Associative Container map Key-value pairs with unique keys, sorted by key
Associative Container multiset Stores sorted elements, allows duplicates
Associative Container unordered_map Key-value pairs with unique keys, unordered
Container Adaptor stack Last-In-First-Out (LIFO) access
Container Adaptor queue First-In-First-Out (FIFO) access
Container Adaptor priority_queue Max-heap (or min-heap with custom comparator)

Complete Example: Using Multiple Containers

This example combines vector, set, and map to demonstrate their respective strengths in storing and managing data.

#include <iostream>
#include <vector>
#include <set>
#include <map>
using namespace std;

int main() {
    vector<int> numbers = {1, 2, 2, 3, 4, 5};
    set<int> unique_numbers(numbers.begin(), numbers.end());
    map<int, string> number_names = {{1, "One"}, {2, "Two"}, {3, "Three"}, {4, "Four"}, {5, "Five"}};

    // Displaying vector elements
    cout << "Vector elements: ";
    for (int num : numbers) {
        cout << num << " ";
    }
    cout << endl;

    // Displaying set elements (unique and sorted)
    cout << "Set elements: ";
    for (int num : unique_numbers) {
        cout << num << " ";
    }
    cout << endl;

    // Displaying map elements (key-value pairs)
    cout << "Map elements:" << endl;
    for (const auto& pair : number_names) {
        cout << pair.first << ": " << pair.second << endl;
    }

    return 0;
}

Sample Output:

Vector elements: 1 2 2 3 4 5 
Set elements: 1 2 3 4 5 
Map elements:
1: One
2: Two
3: Three
4: Four
5: Five

Key Takeaways

  • STL Containers provide various options for storing and managing data effectively.
  • Choose sequence containers (vector, deque, list) for linear storage, associative containers (set, map, unordered_map) for key-based storage, and container adaptors (stack, queue) for special access patterns.

You may also like