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:
- Sequence Containers: Store data in a linear fashion, including vector, deque, list.
- Associative Containers: Use keys to store elements in sorted order, such as set, map, multiset, and multimap.
- 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.