STL, which stands for Standard Template Library, is a powerful set of C++ template classes to provide common data structures and functions such as lists, stacks, arrays, etc. These are extremely handy for C++ programmers as they offer efficient, tested, and standardized implementations of various data structures.
STL containers are pre-defined classes in C++ that store collections of objects. Containers manage the storage space for objects and provide member functions to access and manipulate them. They are templated, meaning you can use them for various data types without rewriting code.
STL containers are categorized into:
Sequence Containers: Store data in a linear order.
Examples: vector
, deque
, list
, array
, forward_list
Associative Containers: Store data as key-value pairs, enabling quick search.
Examples: set
, multiset
, map
, multimap
Derived Containers (Adapters): Provide specific functionality based on existing containers.
Examples: stack
, queue
, priority_queue
Standardization: STL containers are part of the C++ Standard Library, ensuring their availability across different compilers and platforms. This standardization promotes code portability and interoperability.
Efficiency: STL containers are often highly optimized, providing efficient implementations for common operations like insertion, deletion, and retrieval. They are typically designed to strike a balance between speed and memory usage.
Versatility: STL offers a wide range of containers catering to diverse programming needs. Whether you need dynamic arrays (vectors), linked lists (lists), associative arrays (maps), or stacks/queues, there’s a container available.
Safety: Many STL containers provide bounds-checking mechanisms to prevent buffer overflows and memory corruption issues, enhancing code safety.
Ease of Use: STL containers come with a rich set of member functions and algorithms, making them easy to work with. They also support iterators, allowing for convenient traversal and manipulation of elements.
Template-based: STL containers are implemented using templates, allowing for generic programming. This means you can use them with any data type without having to rewrite the container code.
Widely Adopted: STL containers are widely used in the C++ community, which means there is extensive documentation, tutorials, and community support available. This makes it easier for developers to learn and use them effectively.
Time-saving: By leveraging STL containers, developers can avoid reinventing the wheel and focus more on solving the core problem at hand. STL containers provide tested and efficient implementations of common data structures, saving development time.
Overhead: STL containers may introduce some overhead due to their generic nature and additional functionality. In performance-critical scenarios, handcrafted solutions might offer better performance.
Learning Curve: Mastering STL containers and their associated algorithms may require some learning upfront, especially for beginners. Understanding concepts like iterators, algorithms, and container intricacies can take time.
Limited Customization: While STL containers offer a wide range of functionality, they may not always fit specific requirements perfectly. Customization options are limited compared to handcrafted data structures.
Complexity: Some STL containers, especially associative containers like maps and sets, have complex internal implementations. Understanding their underlying data structures and algorithms may require advanced knowledge of computer science concepts.
Debugging: Debugging code that heavily utilizes STL containers can sometimes be challenging, especially when dealing with complex data structures and algorithms.
Fragmentation: Different compilers and library implementations may have slight differences in behavior or performance characteristics for certain STL containers, leading to potential compatibility issues.
Sequence containers in C++ are data structures that store elements in a sequential manner, allowing for efficient access to elements by their position. The key sequence containers in STL include vector
, list
, and deque
.
A vector is a dynamic array that automatically resizes itself when needed, providing fast access to elements. It’s one of the most commonly used containers due to its versatility and efficiency.
#include
#include
int main() {
// Creating a vector of integers
std::vector vec;
// Adding elements to the vector
vec.push_back(10); // Adds element 10 at the end
vec.push_back(20); // Adds element 20 at the end
vec.push_back(30); // Adds element 30 at the end
// Accessing elements
std::cout << "Elements of the vector: ";
for (size_t i = 0; i < vec.size(); ++i) {
std::cout << vec[i] << " "; // Accessing elements using index
}
std::cout << std::endl;
// Size of the vector
std::cout << "Size of the vector: " << vec.size() << std::endl;
// Capacity of the vector
std::cout << "Capacity of the vector: " << vec.capacity() << std::endl;
// Accessing first and last elements
std::cout << "First element: " << vec.front() << std::endl;
std::cout << "Last element: " << vec.back() << std::endl;
// Checking if the vector is empty
std::cout << "Is the vector empty? " << (vec.empty() ? "Yes" : "No") << std::endl;
// Clearing the vector
vec.clear();
std::cout << "Size of the vector after clearing: " << vec.size() << std::endl;
// Resizing the vector
vec.resize(5, 100); // Resizes the vector to size 5 and fills with value 100
std::cout << "Elements of the resized vector: ";
for (int i : vec) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
// output //
Elements of the vector: 10 20 30
Size of the vector: 3
Capacity of the vector: 3
First element: 10
Last element: 30
Is the vector empty? No
Size of the vector after clearing: 0
Elements of the resized vector: 100 100 100 100 100
vec
of integers.push_back()
, we add elements 10, 20, and 30 to the vector.vec[i]
) and front()
/back()
functions.size()
function and its capacity using the capacity()
function.empty()
function.clear()
function.resize()
function.vector()
– Constructs an empty vector.vector(size_type count)
– Constructs a vector with count
copies of a default-initialized value.vector(size_type count, const T& value)
– Constructs a vector with count
copies of a specified value.vector(const vector& other)
– Constructs a vector as a copy of another vector.vector(std::initializer_list<T> init)
– Constructs a vector with the elements from the initializer list.operator[]
– Accesses the element at the specified position.at()
– Accesses the element at the specified position with bounds checking.front()
– Accesses the first element.back()
– Accesses the last element.data()
– Returns a pointer to the underlying array.assign()
– Replaces the contents of the vector with new elements.push_back()
– Adds an element to the end of the vector.pop_back()
– Removes the last element of the vector.insert()
– Inserts elements into the vector at the specified position.erase()
– Removes elements from the vector at the specified position or range.clear()
– Removes all elements from the vector.emplace()
– Constructs and inserts elements into the vector.emplace_back()
– Constructs and appends an element to the end of the vector.resize()
– Resizes the vector to contain a specified number of elements.swap()
– Swaps the contents of two vectors.size()
– Returns the number of elements in the vector.max_size()
– Returns the maximum possible number of elements the vector can hold.capacity()
– Returns the number of elements that can be held in the currently allocated storage.reserve()
– Increases the capacity of the vector to at least a specified amount.shrink_to_fit()
– Reduces the capacity of the vector to fit its size.begin()
– Returns an iterator to the beginning of the vector.end()
– Returns an iterator to the end of the vector.rbegin()
– Returns a reverse iterator to the beginning of the vector.rend()
– Returns a reverse iterator to the end of the vector.empty()
– Checks if the vector is empty.clear()
– Removes all elements from the vector.operator==
, operator!=
, operator<
, operator<=
, operator>
, operator>=
– Comparison operators for vectors.
#include
#include
int main() {
// Construction and Initialization
std::vector vec1; // Constructs an empty vector
std::vector vec2(5, 10); // Constructs a vector with 5 copies of value 10
std::vector vec3 = {1, 2, 3, 4, 5}; // Constructs a vector with initializer list
// Element Access
std::cout << "First element: " << vec3.front() << std::endl; // Accesses the first element
std::cout << "Last element: " << vec3.back() << std::endl; // Accesses the last element
std::cout << "Element at index 2: " << vec3[2] << std::endl; // Accesses element at index 2
std::cout << "Element at index 3: " << vec3.at(3) << std::endl; // Accesses element at index 3
// Modifiers
vec1.push_back(20); // Adds an element to the end
vec1.insert(vec1.begin() + 1, 30); // Inserts an element at the specified position
vec1.pop_back(); // Removes the last element
vec1.erase(vec1.begin()); // Removes the first element
vec1.emplace_back(40); // Constructs and appends an element to the end
vec1.clear(); // Removes all elements
// Capacity
std::cout << "Size of vec2: " << vec2.size() << std::endl; // Returns the number of elements
std::cout << "Capacity of vec2: " << vec2.capacity() << std::endl; // Returns the capacity
vec2.reserve(10); // Increases the capacity to at least 10
vec2.shrink_to_fit(); // Reduces the capacity to fit the size
// Iterators
for (auto it = vec3.begin(); it != vec3.end(); ++it) { // Using iterators to iterate through elements
std::cout << *it << " ";
}
std::cout << std::endl;
// Miscellaneous
std::cout << "Is vec1 empty? " << (vec1.empty() ? "Yes" : "No") << std::endl; // Checks if the vector is empty
std::vector vec4 = {1, 2, 3};
std::vector vec5 = {1, 2, 3};
std::cout << "vec4 == vec5: " << (vec4 == vec5 ? "true" : "false") << std::endl; // Comparison operators for vectors
return 0;
}
// output //
First element: 1
Last element: 5
Element at index 2: 3
Element at index 3: 4
Size of vec2: 5
Capacity of vec2: 5
1 2 3 4 5
Is vec1 empty? Yes
vec4 == vec5: true
A list is a doubly linked list where each element has a pointer to the next and previous elements. It allows for fast insertion and deletion operations anywhere in the container.
#include
#include
int main() {
// Creating a list of integers
std::list myList;
// 1. Adding elements to the list
myList.push_back(10);
myList.push_front(5);
myList.push_back(20);
myList.push_front(2);
// 2. Accessing elements
std::cout << "Elements of the list: ";
for (int i : myList) {
std::cout << i << " ";
}
std::cout << std::endl;
// 3. Removing elements
myList.pop_front(); // Removes the first element
myList.pop_back(); // Removes the last element
// 4. Inserting elements
auto it = myList.begin();
std::advance(it, 2); // Advance iterator to the third element
myList.insert(it, 15); // Insert 15 before the third element
// 5. Erasing elements
it = myList.begin();
std::advance(it, 1); // Advance iterator to the second element
myList.erase(it); // Erase the second element
// 6. Checking if the list is empty
std::cout << "Is the list empty? " << (myList.empty() ? "Yes" : "No") << std::endl;
// 7. Clearing the list
myList.clear();
// Outputting the size of the list after clearing
std::cout << "Size of the list after clearing: " << myList.size() << std::endl;
return 0;
}
// output //
Elements of the list: 2 5 10 15
Is the list empty? No
Size of the list after clearing: 0
push_back()
and push_front()
to add elements 10 and 5 at the back and front of the list respectively.pop_front()
and pop_back()
to remove the first and last elements of the list respectively.insert()
to insert the value 15 before the third element of the list.erase()
to erase the second element of the list.empty()
member function to check if the list is empty.clear()
to remove all elements from the list.std::list<Type> mylist;
– Creates an empty list of elements of type Type
.std::list<Type> mylist (size, value);
– Creates a list with size
elements, each initialized to value
.std::list<Type> mylist (anotherList);
– Creates a copy of anotherList
.front()
– Accesses the first element.back()
– Accesses the last element.begin()
– Returns an iterator to the beginning.end()
– Returns an iterator to the end.rbegin()
– Returns a reverse iterator to the beginning.rend()
– Returns a reverse iterator to the end.push_back(value)
– Adds a new element at the end.pop_back()
– Removes the last element.push_front(value)
– Adds a new element at the beginning.pop_front()
– Removes the first element.insert(iterator, value)
– Inserts a new element before the element at the specified position.erase(iterator)
– Removes the element at the specified position.clear()
– Removes all elements from the list.resize(size)
– Resizes the list to contain size
elements.swap(list)
– Swaps the contents of two lists.empty()
– Checks if the list is empty.size()
– Returns the number of elements in the list.merge(list)
– Merges another list into this one.splice(iterator, list)
– Moves elements from another list into this list.remove(value)
– Removes all elements equal to value
.remove_if(predicate)
– Removes all elements for which the predicate returns true
.reverse()
– Reverses the order of elements in the list.unique()
– Removes consecutive duplicate elements.sort()
– Sorts the elements of the list.
#include
#include
int main() {
// Construction/Initialization
std::list mylist {1, 2, 3, 4, 5};
// Element Access
std::cout << "First element: " << mylist.front() << std::endl;
std::cout << "Last element: " << mylist.back() << std::endl;
// Iterators
std::cout << "Elements:";
for(auto it = mylist.begin(); it != mylist.end(); ++it) {
std::cout << " " << *it;
}
std::cout << std::endl;
// Modifiers
mylist.push_back(6);
mylist.pop_back();
mylist.push_front(0);
mylist.pop_front();
mylist.insert(++mylist.begin(), 10);
mylist.erase(--mylist.end());
// Capacity
std::cout << "Size of list: " << mylist.size() << std::endl;
std::cout << "Is list empty? " << (mylist.empty() ? "Yes" : "No") << std::endl;
// Operations
std::list anotherList {7, 8, 9};
mylist.merge(anotherList);
mylist.remove(3);
mylist.remove_if([](int x) { return x < 5; });
mylist.reverse();
mylist.unique();
mylist.sort();
// Output
std::cout << "Modified list:";
for(const auto& elem : mylist) {
std::cout << " " << elem;
}
std::cout << std::endl;
return 0;
}
// output //
First element: 1
Last element: 5
Elements: 1 2 3 4 5
Size of list: 5
Is list empty? No
Modified list: 4 5 7 8 9 10
mylist
with elements 1, 2, 3, 4, 5
.front()
and back()
) are used to retrieve the first and last elements of the list.begin()
and end()
) are used in a loop to print all elements of the list.push_back()
, pop_back()
, push_front()
, pop_front()
, insert()
, erase()
) are applied to modify the list.size()
and empty()
functions demonstrate capacity operations to check the size and emptiness of the list.merge()
, remove()
, remove_if()
, reverse()
, unique()
, and sort()
are performed on the list to manipulate its contents.A deque (double-ended queue) is similar to a vector but allows fast insertion and deletion at both ends. It’s useful when you need efficient insertion and deletion at the beginning and end of the sequence.
#include
#include
int main() {
// Creating a deque of integers
std::deque myDeque;
// Checking if the deque is empty
std::cout << "Is deque empty? " << (myDeque.empty() ? "Yes" : "No") << std::endl;
// Adding elements to the front and back of the deque
myDeque.push_front(10);
myDeque.push_back(20);
myDeque.push_front(5);
// Accessing the front and back elements of the deque
std::cout << "Front element of the deque: " << myDeque.front() << std::endl;
std::cout << "Back element of the deque: " << myDeque.back() << std::endl;
// Outputting elements of the deque
std::cout << "Elements of the deque: ";
for (int i : myDeque) {
std::cout << i << " ";
}
std::cout << std::endl;
// Outputting the size of the deque
std::cout << "Size of the deque: " << myDeque.size() << std::endl;
// Removing elements from the front and back of the deque
myDeque.pop_front();
myDeque.pop_back();
// Outputting elements of the deque after removal
std::cout << "Elements of the deque after removal: ";
for (int i : myDeque) {
std::cout << i << " ";
}
std::cout << std::endl;
// Clearing the deque
myDeque.clear();
// Checking if the deque is empty after clearing
std::cout << "Is deque empty after clearing? " << (myDeque.empty() ? "Yes" : "No") << std::endl;
return 0;
}
// output //
Is deque empty? Yes
Front element of the deque: 5
Back element of the deque: 20
Elements of the deque: 5 10 20
Size of the deque: 3
Elements of the deque after removal: 10
Is deque empty after clearing? Yes
myDeque
.empty()
function to check if the deque is empty.push_front()
and push_back()
respectively, and 5 is added to the front.front()
and back()
functions.size()
function.pop_front()
and pop_back()
respectively.clear()
function.empty()
function again to check if the deque is empty after clearing.Constructor: Creates an empty deque or initializes it with elements.
Destructor: Destroys all elements in the deque and deallocates the memory allocated by the container.
push_back(): Adds an element to the end of the deque.
push_front(): Adds an element to the front of the deque.
pop_back(): Removes the last element from the deque.
pop_front(): Removes the first element from the deque.
front(): Returns a reference to the first element in the deque.
back(): Returns a reference to the last element in the deque.
begin(): Returns an iterator to the first element in the deque.
end(): Returns an iterator to the position just past the last element in the deque.
rbegin(): Returns a reverse iterator pointing to the last element in the deque (reverse beginning).
rend(): Returns a reverse iterator pointing to the position before the first element in the deque (reverse end).
empty(): Returns true if the deque is empty, false otherwise.
size(): Returns the number of elements in the deque.
clear(): Removes all elements from the deque, leaving it with a size of 0.
erase(): Removes elements from the deque based on a specified range or position.
insert(): Inserts elements into the deque at a specified position.
operator[]: Accesses elements of the deque by index.
#include
#include
int main() {
// Constructor: Creating an empty deque
std::deque myDeque;
// push_back(): Adding elements to the end
myDeque.push_back(10);
myDeque.push_back(20);
myDeque.push_back(30);
// push_front(): Adding elements to the front
myDeque.push_front(5);
myDeque.push_front(2);
// Output the elements of the deque
std::cout << "Deque elements:";
for (auto elem : myDeque) {
std::cout << " " << elem;
}
std::cout << std::endl;
// pop_back(): Removing the last element
myDeque.pop_back();
// pop_front(): Removing the first element
myDeque.pop_front();
// front(): Accessing the first element
std::cout << "First element: " << myDeque.front() << std::endl;
// back(): Accessing the last element
std::cout << "Last element: " << myDeque.back() << std::endl;
// begin() and end(): Iterating through the deque
std::cout << "Iterating through deque:";
for (auto it = myDeque.begin(); it != myDeque.end(); ++it) {
std::cout << " " << *it;
}
std::cout << std::endl;
// empty() and size(): Checking if deque is empty and its size
if (myDeque.empty()) {
std::cout << "Deque is empty" << std::endl;
} else {
std::cout << "Deque size: " << myDeque.size() << std::endl;
}
// clear(): Clearing all elements
myDeque.clear();
std::cout << "Deque size after clearing: " << myDeque.size() << std::endl;
return 0;
}
// output //
Deque elements: 2 5 10 20 30
First element: 5
Last element: 30
Iterating through deque: 2 5 10 20 30
Deque size: 5
Deque size after clearing: 0
myDeque
.push_back()
and push_front()
operations.pop_back()
and the first element is removed using pop_front()
.front()
and back()
respectively.begin()
and end()
.empty()
and size()
.clear()
.In the Standard Template Library (STL), Associative Containers are a group of containers that store data in an ordered structure using keys. These containers provide efficient insertion, deletion, and search operations. The order of the elements is determined based on their keys.
There are four types of associative containers in STL:
set
: Stores unique elements in sorted order.multiset
: Stores duplicate elements in sorted order.map
: Stores key-value pairs where keys are unique and sorted.multimap
: Stores key-value pairs where keys can have duplicates, in sorted order.All associative containers are implemented using Self-Balancing Binary Search Trees (like Red-Black Trees), which ensure logarithmic time complexity (O(log n)
) for search, insertion, and deletion.
The following operations are common across all associative containers:
set
?A set
stores unique elements in sorted order. If you try to insert duplicates, they will be ignored.
set
Operation | Description |
---|---|
insert() | Inserts an element |
erase() | Deletes an element |
find() | Searches for an element |
count() | Returns 1 if key exists, 0 otherwise |
begin() / end() | Iterators to traverse the set |
lower_bound() / upper_bound() | Find range for a key |
clear() | Removes all elements |
set
#include
#include
int main() {
std::set mySet;
// 1. Insertion
mySet.insert(10);
mySet.insert(20);
mySet.insert(30);
mySet.insert(20); // Duplicate, will be ignored
std::cout << "Set after insertion: ";
for (int x : mySet) {
std::cout << x << " ";
}
std::cout << "\n";
// 2. Find and Count
if (mySet.find(20) != mySet.end()) {
std::cout << "20 is found in the set.\n";
}
std::cout << "Count of 30: " << mySet.count(30) << "\n";
// 3. Erase
mySet.erase(10);
std::cout << "Set after erasing 10: ";
for (int x : mySet) {
std::cout << x << " ";
}
std::cout << "\n";
// 4. Lower Bound and Upper Bound
std::cout << "Lower bound of 20: " << *mySet.lower_bound(20) << "\n";
std::cout << "Upper bound of 20: " << *mySet.upper_bound(20) << "\n";
// 5. Clear
mySet.clear();
std::cout << "Set size after clear: " << mySet.size() << "\n";
return 0;
}
Set after insertion: 10 20 30
20 is found in the set.
Count of 30: 1
Set after erasing 10: 20 30
Lower bound of 20: 20
Upper bound of 20: 30
Set size after clear: 0
find()
checks if an element exists.lower_bound()
and upper_bound()
help find range.multiset
?A multiset
allows duplicate elements and maintains them in sorted order.
multiset
The operations are similar to set
:
insert()
erase()
find()
count()
begin()
/ end()
clear()
multiset
#include
#include
int main() {
std::multiset myMultiSet;
// 1. Insertion
myMultiSet.insert(10);
myMultiSet.insert(20);
myMultiSet.insert(10); // Duplicate allowed
std::cout << "Multiset after insertion: ";
for (int x : myMultiSet) {
std::cout << x << " ";
}
std::cout << "\n";
// 2. Count
std::cout << "Count of 10: " << myMultiSet.count(10) << "\n";
// 3. Erase all occurrences of a key
myMultiSet.erase(10);
std::cout << "Multiset after erasing 10: ";
for (int x : myMultiSet) {
std::cout << x << " ";
}
std::cout << "\n";
return 0;
}
Multiset after insertion: 10 10 20
Count of 10: 2
Multiset after erasing 10: 20
multiset
allows duplicate values.count()
returns how many times a value appears.erase()
removes all occurrences of a key.map
?A map
is a container that stores key-value pairs in sorted order. Keys are unique.
map
Operation | Description |
---|---|
insert({key, value}) | Inserts a key-value pair |
erase(key) | Removes a key-value pair |
find(key) | Searches for a key |
at(key) | Access value at a key |
count(key) | Returns 1 if key exists |
clear() | Removes all key-value pairs |
map
#include
#include
1: One
2: Two
Value at key 1: One
After erasing key 2:
1: One
insert()
or []
can insert elements.at()
accesses values safely.erase()
removes key-value pairs.multimap
?A multimap
is an associative container that stores key-value pairs where duplicate keys are allowed. Unlike a map
, multiple entries can exist with the same key, and all keys remain sorted.
multimap
:multimap
allows multiple values for the same key.multimap
cannot be accessed directly using an index.multimap
The following operations are supported by multimap
:
Operation | Description |
---|---|
insert({key, value}) | Inserts a key-value pair into the multimap |
erase(key) | Erases all elements with a specific key |
find(key) | Returns an iterator to the first occurrence of the key |
count(key) | Returns the number of occurrences of a key |
equal_range(key) | Returns a range (pair of iterators) for a key |
lower_bound(key) | Returns iterator to the first key ≥ given key |
upper_bound(key) | Returns iterator to the first key > given key |
begin() / end() | Returns iterators to traverse the multimap |
clear() | Removes all elements |
multimap
#include
#include
Contents of multimap:
1 => Apple
1 => Orange
2 => Banana
3 => Mango
Count of key 1: 2
Values with key 1:
1 => Apple
1 => Orange
Multimap after erasing key 1:
2 => Banana
3 => Mango
Lower bound of key 2: Banana
Upper bound of key 2: Mango
1 => "Apple"
, 1 => "Orange"
) are stored in sorted order based on the key.insert()
to add key-value pairs.for
loop traverses the multimap using iterators.equal_range(1)
returns a pair of iterators (start and end) for all elements with key 1
.erase(1)
removes all key-value pairs where the key is 1
.Lower Bound and Upper Bound:
lower_bound(2)
returns the first occurrence of key 2
.upper_bound(2)
returns the first key greater than 2
(key 3
in this case).Unordered containers are a group of associative containers in the Standard Template Library (STL) that store elements in no particular order. Instead of sorting, they use hash tables for organizing and retrieving elements efficiently.
Container | Description |
---|---|
unordered_map | Key-value pairs with unique keys. |
unordered_multimap | Key-value pairs where duplicate keys are allowed. |
unordered_set | Unique keys only (no duplicates). |
unordered_multiset | Allows duplicate keys (similar to multiset but unordered). |
An unordered_map
is an associative container that stores key-value pairs where keys are unique.
Operation | Description |
---|---|
insert(key, value) | Inserts a key-value pair into the map. If the key already exists, the insertion is ignored. |
erase(key) | Removes the element with the given key. |
find(key) | Returns an iterator to the element with the given key. If not found, returns end(). |
count(key) | Returns the number of elements matching the given key (always 0 or 1 for unordered_map). |
operator[] | Access or insert a key-value pair. If the key does not exist, it inserts it with a default value. |
at(key) | Returns the value associated with the key. Throws an exception if the key is not found. |
clear() | Removes all elements from the map. |
empty() | Returns true if the map is empty. |
size() | Returns the number of elements in the map. |
bucket_count() | Returns the number of buckets in the hash table. |
bucket_size(bucket) | Returns the number of elements in a specific bucket. |
load_factor() | Returns the load factor of the map (number of elements divided by the number of buckets). |
rehash(n) | Resizes the hash table to have at least n buckets. |
#include
#include
#include
int main() {
// Declare an unordered_map
std::unordered_map studentMarks;
// 1. Insert elements
studentMarks["Alice"] = 90;
studentMarks["Bob"] = 85;
studentMarks.insert({"Charlie", 95});
studentMarks.insert({"David", 88});
// 2. Print the unordered_map
std::cout << "Contents of unordered_map:\n";
for (const auto& pair : studentMarks) {
std::cout << pair.first << " => " << pair.second << "\n";
}
// 3. Find an element
std::string key = "Charlie";
if (studentMarks.find(key) != studentMarks.end()) {
std::cout << "\n" << key << " found with marks: " << studentMarks[key] << "\n";
}
// 4. Count an element
std::cout << "\nCount of key 'Bob': " << studentMarks.count("Bob") << "\n";
// 5. Erase an element
studentMarks.erase("David");
std::cout << "\nAfter erasing 'David':\n";
for (const auto& pair : studentMarks) {
std::cout << pair.first << " => " << pair.second << "\n";
}
// 6. Load factor and bucket count
std::cout << "\nNumber of buckets: " << studentMarks.bucket_count();
std::cout << "\nLoad factor: " << studentMarks.load_factor() << "\n";
return 0;
}
// Output
Contents of unordered_map:
Alice => 90
Bob => 85
Charlie => 95
David => 88
Charlie found with marks: 95
Count of key 'Bob': 1
After erasing 'David':
Alice => 90
Bob => 85
Charlie => 95
Number of buckets: 11
Load factor: 0.272727
[]
or insert()
.Accessing Elements:
find()
to check if a key exists.count()
determines if a key is present (returns 1
or 0
).Erasing Elements:
erase(key)
to remove an element by key.Load Factor:
An unordered_multimap
allows duplicate keys.
Operation | Description |
---|---|
insert(key, value) | Inserts a key-value pair into the map. Duplicate keys are allowed. |
erase(key) | Removes all elements matching the given key. |
find(key) | Returns an iterator to the first element with the given key. If not found, returns end(). |
count(key) | Returns the number of elements matching the given key. |
equal_range(key) | Returns a pair of iterators representing the range of elements with the same key. |
clear() | Removes all elements from the multimap. |
empty() | Returns true if the multimap is empty. |
size() | Returns the number of elements in the multimap. |
bucket_count() | Returns the number of buckets in the hash table. |
bucket_size(bucket) | Returns the number of elements in a specific bucket. |
load_factor() | Returns the load factor of the multimap. |
rehash(n) | Resizes the hash table to have at least n buckets. |
#include
#include
int main() {
// Declare an unordered_multimap
std::unordered_multimap myMultiMap;
// Insert elements (duplicate keys allowed)
myMultiMap.insert({1, "Apple"});
myMultiMap.insert({1, "Orange"});
myMultiMap.insert({2, "Banana"});
myMultiMap.insert({3, "Mango"});
std::cout << "Contents of unordered_multimap:\n";
for (const auto& pair : myMultiMap) {
std::cout << pair.first << " => " << pair.second << "\n";
}
// Find range of values for a key
std::cout << "\nValues with key 1:\n";
auto range = myMultiMap.equal_range(1);
for (auto it = range.first; it != range.second; ++it) {
std::cout << it->first << " => " << it->second << "\n";
}
return 0;
}
// Output
Contents of unordered_multimap:
1 => Apple
1 => Orange
2 => Banana
3 => Mango
Values with key 1:
1 => Apple
1 => Orange
An unordered_set
contains unique keys.
Operation | Description |
---|---|
insert(value) | Inserts a unique value into the set. If the value already exists, the insertion is ignored. |
erase(value) | Removes the element matching the given value. |
find(value) | Returns an iterator to the element matching the value. If not found, returns end(). |
count(value) | Returns the number of elements matching the given value (always 0 or 1 for unordered_set). |
clear() | Removes all elements from the set. |
empty() | Returns true if the set is empty. |
size() | Returns the number of elements in the set. |
bucket_count() | Returns the number of buckets in the hash table. |
bucket_size(bucket) | Returns the number of elements in a specific bucket. |
load_factor() | Returns the load factor of the set. |
rehash(n) | Resizes the hash table to have at least n buckets. |
#include
#include
int main() {
std::unordered_set mySet;
// Insert elements
mySet.insert(10);
mySet.insert(20);
mySet.insert(10); // Duplicate ignored
mySet.insert(30);
std::cout << "Contents of unordered_set:\n";
for (const int& num : mySet) {
std::cout << num << " ";
}
// Check if an element exists
if (mySet.find(20) != mySet.end()) {
std::cout << "\n\n20 exists in the set.";
}
return 0;
}
// Output
Contents of unordered_set:
10 20 30
20 exists in the set.
An unordered_multiset
allows duplicate keys.
Operation | Description |
---|---|
insert(value) | Inserts a value into the multiset. Duplicate values are allowed. |
erase(value) | Removes all elements matching the given value. |
find(value) | Returns an iterator to the first element matching the value. If not found, returns end(). |
count(value) | Returns the number of elements matching the given value. |
equal_range(value) | Returns a pair of iterators representing the range of elements with the same value. |
clear() | Removes all elements from the multiset. |
empty() | Returns true if the multiset is empty. |
size() | Returns the number of elements in the multiset. |
bucket_count() | Returns the number of buckets in the hash table. |
bucket_size(bucket) | Returns the number of elements in a specific bucket. |
load_factor() | Returns the load factor of the multiset. |
rehash(n) | Resizes the hash table to have at least n buckets. |
#include
#include
int main() {
std::unordered_multiset myMultiSet;
// Insert elements (duplicates allowed)
myMultiSet.insert(10);
myMultiSet.insert(20);
myMultiSet.insert(10);
myMultiSet.insert(30);
std::cout << "Contents of unordered_multiset:\n";
for (const int& num : myMultiSet) {
std::cout << num << " ";
}
return 0;
}
// Output
Contents of unordered_multiset:
10 10 20 30
Derived containers in C++ Standard Template Library (STL) are built using existing containers and provide additional functionalities. These containers are specifically tailored to suit specialized operations like priority management, queue-based data handling, or stack-based workflows.
The derived containers include:
Let’s explore each derived container in detail, including their operations, practical examples, and explanations.
A stack is a Last In, First Out (LIFO) container. It allows insertion and deletion only at the top of the stack.
Operation | Description |
---|---|
push(element) | Inserts an element at the top of the stack. |
pop() | Removes the top element from the stack. |
top() | Returns the top element of the stack. |
empty() | Checks whether the stack is empty. |
size() | Returns the number of elements in the stack. |
#include
#include
using namespace std;
int main() {
stack s;
// Push elements
s.push(10);
s.push(20);
s.push(30);
// Display the top element
cout << "Top element: " << s.top() << endl;
// Pop an element
s.pop();
cout << "After popping, top element: " << s.top() << endl;
// Check size and empty status
cout << "Stack size: " << s.size() << endl;
cout << "Is stack empty? " << (s.empty() ? "Yes" : "No") << endl;
return 0;
}
// Output
Top element: 30
After popping, top element: 20
Stack size: 2
Is stack empty? No
A queue is a First In, First Out (FIFO) container. Elements are inserted at the back and removed from the front.
Operation | Description |
---|---|
push(element) | Inserts an element at the back of the queue. |
pop() | Removes the element at the front of the queue. |
front() | Returns the element at the front of the queue. |
back() | Returns the element at the back of the queue. |
empty() | Checks whether the queue is empty. |
size() | Returns the number of elements in the queue. |
#include
#include
using namespace std;
int main() {
queue q;
// Push elements
q.push(10);
q.push(20);
q.push(30);
// Display the front and back elements
cout << "Front element: " << q.front() << endl;
cout << "Back element: " << q.back() << endl;
// Pop an element
q.pop();
cout << "After popping, front element: " << q.front() << endl;
// Check size and empty status
cout << "Queue size: " << q.size() << endl;
cout << "Is queue empty? " << (q.empty() ? "Yes" : "No") << endl;
return 0;
}
// Output
Front element: 10
Back element: 30
After popping, front element: 20
Queue size: 2
Is queue empty? No
A priority_queue is a container where elements are arranged in descending order by default (max-heap). The highest-priority element is at the top.
Operation | Description |
---|---|
push(element) | Inserts an element and arranges it in order of priority. |
pop() | Removes the highest-priority element. |
top() | Returns the highest-priority element. |
empty() | Checks whether the priority queue is empty. |
size() | Returns the number of elements in the priority queue. |
#include
#include
using namespace std;
int main() {
priority_queue pq;
// Push elements
pq.push(10);
pq.push(20);
pq.push(15);
// Display the top element
cout << "Top element: " << pq.top() << endl;
// Pop an element
pq.pop();
cout << "After popping, top element: " << pq.top() << endl;
// Check size and empty status
cout << "Priority queue size: " << pq.size() << endl;
cout << "Is priority queue empty? " << (pq.empty() ? "Yes" : "No") << endl;
return 0;
}
// Output
Top element: 20
After popping, top element: 15
Priority queue size: 2
Is priority queue empty? No
A deque allows insertion and deletion at both ends.
Operation | Description |
---|---|
push_front(element) | Inserts an element at the front of the deque. |
push_back(element) | Inserts an element at the back of the deque. |
pop_front() | Removes the front element of the deque. |
pop_back() | Removes the back element of the deque. |
front() | Returns the front element of the deque. |
back() | Returns the back element of the deque. |
empty() | Checks whether the deque is empty. |
size() | Returns the number of elements in the deque. |
clear() | Removes all elements from the deque. |
operator[] | Accesses an element by index. |
#include
#include
using namespace std;
int main() {
deque d;
// Push elements at both ends
d.push_back(10);
d.push_front(20);
// Display the front and back elements
cout << "Front element: " << d.front() << endl;
cout << "Back element: " << d.back() << endl;
// Pop elements from both ends
d.pop_front();
cout << "After popping front, front element: " << d.front() << endl;
// Add more elements and access by index
d.push_back(30);
cout << "Element at index 0: " << d[0] << endl;
return 0;
}
// Output
Front element: 20
Back element: 10
After popping front, front element: 10
Element at index 0: 10
STL containers provide a versatile and efficient way to manage collections of data in C++. By offering various types such as sequence containers, associative containers, and unordered containers, STL enables developers to choose the right tool for specific use cases. Their integration with STL algorithms and iterators ensures seamless data manipulation, making them indispensable for modern C++ programming. Happy coding !❤️