A Comprehensive Technical Report on the C++ Standard
Template Library: An Analysis Based on the "takeUforward"
Tutorial
Section 1: The Architecture of the Standard Template Library
This section establishes the foundational principles of the C++ Standard Template
Library (STL), framing it not as a mere collection of tools but as a cohesive ecosystem
built on the philosophy of generic programming.
1.1 Introduction to the STL
The C++ Standard Template Library (STL) is a sophisticated and powerful set of C++
template classes and functions. It provides programmers with pre-defined, highly
optimized implementations of common data structures and algorithms, such as lists,
stacks, dynamic arrays, and sorting routines.1 The fundamental value of the STL lies in
its abstraction; it allows developers to focus on solving complex, high-level logical
problems rather than expending effort on re-implementing and debugging
fundamental data management components.1 This focus on reuse and reliability has
made the STL an indispensable tool in modern C++, particularly in
performance-critical domains like competitive programming, where its speed and
well-defined complexities offer a significant advantage.1
1.2 The Core Philosophy: Generic Programming
The STL is built upon three core pillars: Containers, Algorithms, and Iterators.2 The
genius of its design lies in how these components are decoupled to work together, a
principle known as generic programming.4
● Containers are objects that store collections of other objects, representing data
structures like std::vector or std::map.2
● Algorithms are functions that perform operations on containers, such as std::sort
or std::find.2
● Iterators are objects that act like pointers, providing a uniform way to access
elements within a container, effectively bridging the gap between containers and
algorithms.2
This separation allows for remarkable flexibility. An algorithm does not need to know
the internal implementation of a container; it only needs a pair of iterators defining a
range of elements to work on. This means a single algorithm, like std::sort, can be
applied to any container that provides the necessary type of iterator, embodying the
"write less, do more" principle of efficient software development.4
1.3 A Primer on Time Complexity and Big-O Notation
To use the STL effectively, one must understand how to measure the performance of
its components. The industry standard for this is Big-O notation, which describes the
upper bound of an algorithm's runtime or memory usage as the input size, denoted as
'n', grows.7 Key complexities frequently referenced include:
● Constant Time 'O(1)': The operation takes the same amount of time regardless
of the container's size. This is the ideal complexity.3
● Logarithmic Time 'O(logn)': The runtime grows logarithmically with the size of
the container. This is extremely efficient and scalable for very large datasets.7
● Linear Time 'O(n)': The runtime grows directly in proportion to the number of
elements. This is a common and acceptable complexity for many operations.7
An understanding of these complexities is critical for selecting the right STL tool for a
given task, as choosing a container with an inappropriate time complexity for a
frequent operation can lead to severe performance bottlenecks.
1.4 Deeper Insights: The "Why" Behind the Architecture
The architecture of the STL is a result of deliberate and insightful design choices. The
separation of concerns between data storage (containers) and data processing
(algorithms) is not accidental; it is the key to the library's power and reusability. An
algorithm, such as std::sort or std::binary_search, is designed to operate on a range
specified by iterators (e.g., container.begin(), container.end()).6 Because diverse
containers like
std::vector, std::list, and std::deque all provide this common iterator interface, the
algorithm remains agnostic to the container's underlying structure.5 This design
prevents the need for container-specific functions like a
vector_sort or list_find, thereby promoting massive code reuse and simplifying the
library's interface.4
Furthermore, the tutorial's presentation style, characterized by the frequent inclusion
of the non-standard <bits/stdc++.h> header and a relentless focus on the Big-O
complexity of every function, points to an audience primarily concerned with
competitive programming.8 The
<bits/stdc++.h> header is a GCC-specific shortcut that includes nearly all standard
library files, saving time in a contest setting but considered poor practice in
professional software engineering due to its negative impact on compilation time and
code portability. The emphasis on time complexity is paramount in competitive
programming, where solutions must execute within strict time limits. While this report
will adhere to the technical details presented, it is important to recognize this context
and distinguish between contest shortcuts and professional coding standards.
Section 2: Foundational and Sequence Containers
This section provides an exhaustive analysis of the primary containers for storing
sequential data, detailing their internal mechanics and operational trade-offs.
2.1 std::pair: The Two-Element Tuple
The std::pair, found in the <utility> header, is a fundamental utility container that
bundles two values, which may be of different types, into a single object.11
● Declaration and Initialization: A pair can be created in several ways, including
brace-initialization (std::pair<int, std::string> p = {1, "example"};) or by using the
std::make_pair() helper function (auto p = std::make_pair(1, "example");).11
● Member Access and Operations: The two elements are accessed via public
members .first and .second.3 Pairs support lexicographical comparison operators (
<, ==, etc.), where the .first elements are compared, and only if they are equal are
the .second elements compared.13 This makes them suitable for use as keys in
sorted containers. Their primary use case is as the element type for
std::map and for returning multiple values from a function.4
2.2 std::vector: The Quintessential Dynamic Array
The std::vector is arguably the most used STL container. It provides the functionality
of a dynamic array that can grow or shrink in size as needed.3 Its elements are
guaranteed to be stored in contiguous memory, which allows for highly efficient
random access.5
● Declaration and Initialization: Vectors can be created empty, from an initializer
list (std::vector<int> v = {1, 2, 3};), with a specific size and initial value
(std::vector<int> v(5, 100);), or by copying another vector.15
● Key Member Functions and Complexity:
○ push_back(value): Adds an element to the end. This operation has an
amortized constant time complexity, 'O(1)'.8 While an individual push may
trigger a reallocation (a linear time operation), the cost is averaged out over
many insertions.
○ pop_back(): Removes the last element in 'O(1)' time.3
○ size(): Returns the number of elements in 'O(1)' time.3
○ Access (operator or .at()): Direct access to any element is an 'O(1)' operation
due to contiguous storage.5
○ insert(iterator, value) and erase(iterator): Inserting or removing an element
from the middle of a vector is a slow, 'O(n)' operation, as it requires shifting all
subsequent elements.3
2.3 std::list: The Bidirectional Linked List
The std::list is implemented as a doubly-linked list, meaning its elements are not
stored in contiguous memory.5 This structural difference leads to a completely
different performance profile compared to
std::vector.
● Strengths and Weaknesses: Because elements are not contiguous, a std::list
does not support random access; retrieving an element by its position is an 'O(n)'
operation. However, its key strength is the ability to perform insertions and
deletions anywhere within the list in constant time, 'O(1)', provided an iterator to
the location is available.5
● Key Member Functions and Complexity:
○ push_front(value) and pop_front(): 'O(1)' insertion and removal from the
beginning of the list.10
○ push_back(value) and pop_back(): 'O(1)' insertion and removal from the end
of the list.10
○ front() and back(): 'O(1)' access to the first and last elements.10
2.4 std::deque: The Versatile Double-Ended Queue
The std::deque (double-ended queue) offers a hybrid of std::vector and std::list
functionalities. It allows for fast, 'O(1)' insertion and deletion at both its beginning and
its end, a feature std::vector lacks.4 Unlike
std::list, it also provides 'O(1)' random access to elements. It achieves this through a
more complex internal structure, typically a sequence of individually allocated
fixed-size arrays.
2.5 Deeper Insights: The emplace_back vs. push_back Distinction
A subtle but important C++11 optimization relevant to sequence containers is the
difference between push_back and emplace_back.19 When adding an object to a
container,
push_back first creates a temporary object from the provided arguments, and then
moves or copies that temporary object into the container's memory. For example,
vec.push_back(MyClass(arg1, arg2)); involves a constructor call to create the
temporary, followed by a move constructor call.
In contrast, emplace_back is a variadic template function that accepts the constructor
arguments directly. It forwards these arguments to the object's constructor, which is
called in-place within the container's allocated memory. For example,
vec.emplace_back(arg1, arg2); constructs the object just once, directly where it is
needed. By avoiding the creation and subsequent destruction of a temporary object,
emplace functions can offer a significant performance improvement, especially for
complex objects with expensive construction or copy/move operations.12
Section 3: Container Adaptors: Specialized Interfaces
Container adaptors are not new container types themselves but are wrappers that
provide a restricted, specialized interface to an underlying sequence container. They
are designed to enforce specific data access patterns.
3.1 std::stack: The Last-In, First-Out (LIFO) Abstraction
A std::stack enforces a Last-In, First-Out (LIFO) access policy.2 By default, it is
implemented using a
std::deque as its underlying container, though this can be changed to std::vector or
std::list.4
● Core Operations (All 'O(1)'):
○ push(value): Adds an element to the top of the stack.3
○ pop(): Removes the element from the top.3
○ top(): Returns a reference to the top element without removing it.3
○ empty() and size(): Check if the stack is empty and return its size,
respectively.21
3.2 std::queue: The First-In, First-Out (FIFO) Abstraction
A std::queue enforces a First-In, First-Out (FIFO) access policy, modeling a real-world
queue.2 Like
std::stack, it uses std::deque as its default underlying container.4
● Core Operations (All 'O(1)'):
○ push(value): Adds an element to the back of the queue (enqueue).3
○ pop(): Removes the element from the front of the queue (dequeue).3
○ front(): Returns a reference to the front element.3
○ back(): Returns a reference to the back element.23
3.3 std::priority_queue: The Heap-Based Priority Abstraction
A std::priority_queue is an adaptor where elements are ordered by priority rather than
insertion order. The pop() operation always removes the element with the highest
priority.3 It is implemented as a binary heap, using
std::vector as its underlying container by default.24
● Max-Heap (Default): The default std::priority_queue is a max-heap, where the
largest element is considered the highest priority and is always at the top.24
○ Declaration: std::priority_queue<int> pq;
○ Operations: push(value) and pop() have 'O(logn)' complexity, while top() is
'O(1)'.8
● Min-Heap: To create a min-heap, where the smallest element has the highest
priority, the declaration requires specifying the underlying container and a
comparator.
○ Declaration: std::priority_queue<int, std::vector<int>, std::greater<int>> pq;.24
It is crucial to understand that these adaptors are intentionally restrictive. They do not
provide iterators and thus cannot be traversed with standard loops.4 The only way to
inspect all elements is to destructively (or on a copy) pop elements one by one.12 This
design enforces the intended access pattern (LIFO, FIFO, or priority-based),
preventing operations that would violate the logical abstraction of the data structure.
Section 4: Associative Containers: Ordered Data Management
Associative containers automatically maintain their elements in a sorted order based
on keys, which enables highly efficient search, insertion, and deletion operations.
4.1 std::set and std::multiset
A std::set stores a collection of unique elements, sorted in ascending order by
default.2 Its counterpart,
std::multiset, functions identically but allows for multiple equivalent (duplicate)
elements.6
● Underlying Implementation: Both are typically implemented as self-balancing
binary search trees (e.g., Red-Black Trees), which guarantees that the primary
operations maintain a logarithmic time complexity relative to the number of
elements in the container.4
● Key Operations (all 'O(logn)'):
○ insert(value): Inserts an element while maintaining the sorted order. In a
std::set, if the element already exists, the operation is ignored.20
○ erase(value): Removes one (for set) or all (for multiset) instances of a given
value.20
○ find(value): Searches for an element and returns an iterator to it if found;
otherwise, it returns an iterator to .end().3
○ count(value): Returns 1 if the element exists in a std::set, and the total number
of occurrences in a std::multiset.27
○ lower_bound(value) and upper_bound(value): These functions are essential
for performing efficient range-based queries on the sorted data.
4.2 std::map and std::multimap
A std::map stores key-value pairs, where each key is unique and the elements are
sorted based on these keys.2
std::multimap is similar but permits multiple entries with the same key.4
● Underlying Implementation: Like sets, maps are also implemented using
self-balancing binary search trees, ensuring 'O(logn)' performance for key
operations.4
● Key Operations:
○ Insertion: Elements can be inserted using m.insert({key, value}) in 'O(logn)'
time.29
○ Access and Update: The subscript operator m[key] is a common way to
access or assign a value. It has 'O(logn)' complexity. A critical behavior of this
operator is that if the key does not exist, it will be inserted into the map with a
default-constructed value, and a reference to this new value is returned.29 For
safe, read-only access,
m.at(key) should be used, as it provides bounds checking and will throw an
exception if the key is not found, rather than performing an insertion.29
○ Search and Deletion: find(key) and erase(key) also operate in 'O(logn)'
time.28
Section 5: Unordered Associative Containers: Hashing for
Performance
Unordered containers provide an alternative to their ordered counterparts, prioritizing
raw performance over sorted data maintenance.
5.1 std::unordered_set and std::unordered_map
std::unordered_set and std::unordered_map provide the same interfaces as std::set
and std::map, respectively, but with one fundamental difference: they do not store
elements in any particular order.2 The element order is arbitrary and is determined by
the container's internal hashing mechanism.
● Underlying Implementation: These containers are implemented using hash
tables.2 Each element's key is passed to a hash function, which computes an
index where the element should be stored.
● Performance:
○ Average Case: Due to the direct computation provided by hashing, the time
complexity for insertion, deletion, and search operations is constant, 'O(1)', on
average.8
○ Worst Case: If the hash function produces the same index for many different
keys (an event known as a hash collision), the container must handle these
collisions, often by storing the colliding elements in a list. In this scenario,
performance for all major operations can degrade to linear time, 'O(n)'.31
5.2 Deeper Insights: The Critical Trade-off
The choice between an ordered container (like std::map) and an unordered container
(like std::unordered_map) is one of the most common and critical performance
decisions a C++ developer makes. The decision hinges on a clear trade-off between
functionality and speed.
The path to choosing the correct container involves answering one key question: is
the order of elements important? If the problem requires elements to be iterated in a
sorted sequence, or if range-based queries (e.g., finding all elements with keys
between X and Y using lower_bound and upper_bound) are necessary, then an
ordered container like std::map or std::set is the only viable choice.8 The guaranteed '
O(logn)' complexity is the price paid for this ordering functionality.
However, if the sole requirement is to perform fast key-based lookups, insertions, and
deletions, and the element order is irrelevant, the unordered versions are vastly
superior. Their 'O(1)' average-case performance makes them the default choice for
implementing dictionaries, frequency counters, and caches where speed is the
primary concern.31 This choice between a balanced binary search tree and a hash
table is a fundamental concept in data structure and algorithm design.
Section 6: A Deep Dive into Essential STL Algorithms
This section moves from data storage to data manipulation, focusing on the key
algorithms presented in the tutorial.
6.1 std::sort: Mastering Sorting
The std::sort algorithm is a versatile and efficient tool for sorting elements within a
range defined by two random-access iterators.6
● Functionality and Complexity: By default, std::sort arranges elements in
ascending order using the < operator for comparison. It is typically implemented
using IntroSort, a hybrid algorithm that combines the strengths of QuickSort,
HeapSort, and InsertionSort to provide excellent average-case performance of
'O(nlogn)'.33
● Custom Comparators: The behavior of std::sort can be customized by providing
a third argument: a comparison function (or functor/lambda). This binary function
must accept two elements and return true if the first element should be ordered
before the second.33
○ Descending Order: To sort in descending order, one can pass the
std::greater<T>() functor or a custom function: bool comp(int a, int b) { return
a > b; }.3
○ Sorting Complex Types: This is particularly useful for user-defined types.
For a std::vector<std::pair<int, int>>, one can sort based on the second
element of the pair by defining a comparator that specifically compares
p1.second and p2.second.33
6.2 Binary Search and Related Functions
The STL provides a suite of powerful binary search algorithms that operate on sorted
ranges with 'O(logn)' complexity. A critical prerequisite is that the container or range
must already be sorted according to the same comparison criterion.9
● binary_search(first, last, value): This function checks for the presence of a value
within a sorted range and returns a simple boolean true or false.9
● lower_bound(first, last, value): This function is more powerful. It returns an iterator
pointing to the first element in the range that is not less than the given value.9
● upper_bound(first, last, value): This function returns an iterator pointing to the
first element in the range that is greater than the given value.9
While binary_search provides a simple existence check, lower_bound and
upper_bound offer far more utility. Since they return an iterator, they not only confirm
an element's potential presence but also reveal its position. This allows for efficient
insertion of new elements while maintaining sort order. Furthermore, the distance
between the iterators returned by lower_bound and upper_bound for a given value
can be used to count the number of occurrences of that value in the range, making
them more versatile than a simple search.
6.3 Generating Permutations with next_permutation
The std::next_permutation algorithm is a fascinating tool that rearranges the elements
in a range into the next lexicographically greater permutation.3
● Usage Pattern: To generate all unique permutations of a sequence, a specific
pattern must be followed. First, the sequence must be sorted in ascending order.
Then, std::next_permutation can be called repeatedly inside a do-while loop. The
loop continues as long as the function returns true, which it does for every
successful permutation. When the sequence reaches its final, lexicographically
largest arrangement (e.g., sorted in descending order), the function transforms it
back to the very first permutation (sorted ascending) and returns false,
terminating the loop.3
For example, to print all permutations of the string "abc":
C++
std::string s = "abc";
std::sort(s.begin(), s.end()); // Start with the first permutation: "abc"
do {
std::cout
<< s << std::endl;
} while (std::next_permutation(s.begin(), s.end()));
This will output: abc, acb, bac, bca, cab, cba.
Section 7: A Practical Guide to STL Performance and Selection
This final section synthesizes the report's findings into actionable, comparative guides
to aid in the practical application of the STL.
7.1 Comparative Analysis of STL Containers
The choice of container has a profound impact on an application's performance. The
following table summarizes the time complexities of the most common operations
across key STL containers, providing a quick reference for making informed design
decisions.
Operation std::vector std::list std::set / std::unordered_
std::map set /
std::unordered_
map
Access (by 'O(1)' 'O(n)' 'O(logn)' 'O(1)' avg, 'O(n)'
index/key) worst
Search (by 'O(n)' 'O(n)' 'O(logn)' 'O(1)' avg, 'O(n)'
value) worst
Insertion (at 'O(1)' amortized 'O(1)' 'O(logn)' 'O(1)' avg, 'O(n)'
end) worst
Insertion (at 'O(n)' 'O(1)' 'O(logn)' 'O(1)' avg, 'O(n)'
middle) worst
Deletion (from 'O(1)' 'O(1)' 'O(logn)' 'O(1)' avg, 'O(n)'
end) worst
Deletion (from 'O(n)' 'O(1)' 'O(logn)' 'O(1)' avg, 'O(n)'
middle) worst
7.2 A Decision-Making Framework for Choosing the Right Container
Knowing the complexity numbers is the first step; applying them to solve a problem is
the goal. This guide translates the performance data into a practical decision-making
framework.
If you need... Consider Using... Because... (Key But Be Aware Of...
Strength) (Weakness)
Fast random access std::vector 'O(1)' random access. Slow 'O(n)'
by index and fast insertion/deletion in
addition/removal at the middle.
the end.
Frequent std::list 'O(1)' Slow 'O(n)' search
insertion/deletion insertion/deletion and no random
anywhere in the with an iterator. access.
sequence.
Fast key-based std::map / std::set Data is always sorted; 'O(logn)' complexity
lookup AND need enables range for all major
elements to be in queries. operations.
sorted order.
The absolute fastest std::unordered_map / 'O(1)' average time No element ordering;
key-based lookup, std::unordered_set for lookup, insert, worst-case 'O(n)'
and order does not delete. performance.
matter.
A strict LIFO or FIFO std::stack / Enforces a clean, Limited functionality;
access pattern. std::queue simple, and safe no direct iteration.
interface.
Works cited
1. C++ STL Tutorial : Most frequent used STL Containers/Algorithms ..., accessed
August 1, 2025,
https://takeuforward.org/c/c-stl-tutorial-most-frequent-used-stl-containers/
2. C++ Standard Template Library (STL) - GeeksforGeeks, accessed August 1, 2025,
https://www.geeksforgeeks.org/cpp/the-c-standard-template-library-stl/
3. Complete C++ STL in 1 Video | Time Complexity and Notes Sider ..., accessed
August 1, 2025,
https://sider.ai/kn/tools/video/AI-video-shortener/explore/48ee9fcb-4d78-4f32-ac
59-e507e54ce6c3
4. The C++ Standard Template Library - Distributed Object Computing ..., accessed
August 1, 2025, https://www.dre.vanderbilt.edu/~schmidt/PDF/stl.pdf
5. C++ Standard Template Library - Washington, accessed August 1, 2025,
https://courses.cs.washington.edu/courses/cse333/18su/lectures/14-c++-STL.pdf
6. C++ STL Tutorial - Tutorialspoint, accessed August 1, 2025,
https://www.tutorialspoint.com/cplusplus/cpp_stl_tutorial.htm
7. C++ STL Containers: Choose your containers wisely - DEV Community, accessed
August 1, 2025,
https://dev.to/pratikparvati/c-stl-containers-choose-your-containers-wisely-4lc4
8. Analysis of time and space complexity of C++ STL containers - GeeksforGeeks,
accessed August 1, 2025,
https://www.geeksforgeeks.org/cpp/analysis-of-time-and-space-complexity-of-s
tl-containers/
9. std::binary_search - cppreference.com - Mooshak, accessed August 1, 2025,
https://mooshak.dcc.fc.up.pt/~oni-judge/doc/cppreference/reference/en/cpp/algo
rithm/binary_search.html
10.List in C++ STL - GeeksforGeeks, accessed August 1, 2025,
https://www.geeksforgeeks.org/cpp/list-cpp-stl/
11. Pair in C++ STL - GeeksforGeeks, accessed August 1, 2025,
https://www.geeksforgeeks.org/cpp/pair-in-cpp-stl/
12.Stack in C++ STL - GeeksforGeeks, accessed August 1, 2025,
https://www.geeksforgeeks.org/cpp/stack-in-cpp-stl/
13.C++ STL: pair (Complete Guide) - work@tech, accessed August 1, 2025,
https://workat.tech/problem-solving/tutorial/cpp-stl-pair-complete-guide-ia62jqg
0dszu
14.Pair in C++: A Comprehensive Guide to Storing and Manipulating Data Pairs -
AlgoCademy, accessed August 1, 2025,
https://algocademy.com/blog/pair-in-c-a-comprehensive-guide-to-storing-and-
manipulating-data-pairs/
15.Vector in C++ STL - GeeksforGeeks, accessed August 1, 2025,
https://www.geeksforgeeks.org/cpp/vector-in-cpp-stl/
16.C++ Vectors (With Examples) - Programiz, accessed August 1, 2025,
https://www.programiz.com/cpp-programming/vectors
17.size() complexity of STL containers in G++: which containers are O(n)? - Stack
Overflow, accessed August 1, 2025,
https://stackoverflow.com/questions/8469218/size-complexity-of-stl-containers-i
n-g-which-containers-are-on
18.C++ List (With Examples) - Programiz, accessed August 1, 2025,
https://www.programiz.com/cpp-programming/list
19.C++ STL Complete Tutorial | Standard Template Library - One Shot - YouTube,
accessed August 1, 2025, https://www.youtube.com/watch?v=okhdtEk1iKk
20.Set in C++ STL - GeeksforGeeks, accessed August 1, 2025,
https://www.geeksforgeeks.org/cpp/set-in-cpp-stl/
21.C++ STL: stack (Complete Guide), accessed August 1, 2025,
https://workat.tech/problem-solving/tutorial/cpp-stl-stack-complete-guide-2gm8
84xcs902
22.C++ STL: queue (Complete Guide) - work@tech, accessed August 1, 2025,
https://workat.tech/problem-solving/tutorial/cpp-stl-queue-complete-guide-7kk1
6h4zos8l
23.Queue in C++ STL - GeeksforGeeks, accessed August 1, 2025,
https://www.geeksforgeeks.org/cpp/queue-cpp-stl/
24.C++ STL: priority_queue (Complete Guide) - work@tech, accessed August 1,
2025,
https://workat.tech/problem-solving/tutorial/cpp-stl-priority-queue-complete-gui
de-bnwvwagtxrws
25.priority_queue in C++ STL - Tutorial - takeUforward, accessed August 1, 2025,
https://takeuforward.org/c/priority-queue-in-c-stl
26.Understanding the Need for C++ Set: Features and Use Cases | by Sofia Sondh |
Medium, accessed August 1, 2025,
https://medium.com/@sofiasondh/understanding-the-need-for-c-set-features-a
nd-use-cases-83d4baafbb5e
27.Multiset in STL in C++ STL - Standard template library - CodeChef, accessed
August 1, 2025,
https://www.codechef.com/learn/course/cpp-stl/CSTL05/problems/MULTISET
28.Complete C++ STL in 1 Video | Time Complexity and Notes - YouTube, accessed
August 1, 2025, https://www.youtube.com/watch?v=RRVYpIET_RU
29.Map in C++ STL - GeeksforGeeks, accessed August 1, 2025,
https://www.geeksforgeeks.org/cpp/map-associative-containers-the-c-standard
-template-library-stl/
30.C++ Map - Programiz, accessed August 1, 2025,
https://www.programiz.com/cpp-programming/map
31.Unordered Map in C++ STL - GeeksforGeeks, accessed August 1, 2025,
https://www.geeksforgeeks.org/unordered_map-in-cpp-stl/
32.STL containers and algorithms are not convenient enough : r/cpp - Reddit,
accessed August 1, 2025,
https://www.reddit.com/r/cpp/comments/86icdm/stl_containers_and_algorithms_
are_not_convenient/
33.sort() in C++ STL - GeeksforGeeks, accessed August 1, 2025,
https://www.geeksforgeeks.org/sort-c-stl/
34.std::binary_search() in C++ STL - GeeksforGeeks, accessed August 1, 2025,
https://www.geeksforgeeks.org/cpp/binary-search-algorithms-the-c-standard-te
mplate-library-stl/
35.std::binary_search - cppreference.com - C++ Reference, accessed August 1,
2025, https://en.cppreference.com/w/cpp/algorithm/binary_search.html
36.std::next_permutation - cppreference.com - C++ Reference, accessed August 1,
2025, https://en.cppreference.com/w/cpp/algorithm/next_permutation.html
37.std::next_permutation - cppreference.com, accessed August 1, 2025,
http://naipc.uchicago.edu/2014/ref/cppreference/en/cpp/algorithm/next_permutat
ion.html