STLs
STLs
STLs
Let's go through the pros and cons of each of these data structures:
1. Vector:
Pros:
Cons:
Resizing can be expensive when the vector grows beyond its capacity.
Pros:
Cons:
3. List:
Pros:
Cons:
4. Forward List:
Pros:
Cons:
STLs 1
5. Pair:
Pros:
Cons:
Limited to two elements, not suitable for more complex data structures.
6. Set:
Pros:
Cons:
Elements are usually ordered, which may not be desired in all cases.
7. Map:
Pros:
Cons:
Elements are usually ordered, which may not be desired in all cases.
Pros:
Cons:
Pros:
Cons:
10. Stack:
STLs 2
Pros:
Cons:
11. Queue:
Pros:
Cons:
Pros:
Elements are stored in a way that allows retrieval of the highest-priority element efficiently.
Cons:
Here's a summary of the time complexities for common operations on these data structures
1. Vector:
Search: O(n)
#include <vector>
std::vector<int> myVector = {1, 2, 3, 4, 5};
myVector.push_back(6); // Add element to the end (Amortized O(1))
myVector.pop_back(); // Remove element from the end (O(1))
int thirdElement = myVector[2]; // Access element by index (O(1))
2. Deque:
STLs 3
Insertion/Deletion (beginning/end): O(1)
Search: O(n)
#include <deque>
std::deque<int> myDeque = {1, 2, 3, 4, 5};
myDeque.push_back(6); // Add element to the end (Amortized O(1))
myDeque.push_front(0); // Add element to the beginning (Amortized O(1))
int firstElement = myDeque.front(); // Access the first element (O(1))
3. List:
Search: O(n)
#include <list>
std::list<int> myList = {1, 2, 3, 4, 5};
myList.push_back(6); // Add element to the end (O(1))
myList.insert(++myList.begin(), 10); // Insert 10 after the first element (O(1))
myList.remove(3); // Remove all occurrences of 3 (O(n))
4. Forward List:
Search: O(n)
#include <forward_list>
std::forward_list<int> myForwardList = {1, 2, 3, 4, 5};
myForwardList.push_front(0); // Add element to the beginning (O(1))
myForwardList.insert_after(myForwardList.begin(), 10); // Insert 10 after the first element (O(1))
5. Pair:
Access: O(1)
#include <utility>
std::pair<std::string, int> myPair = std::make_pair("Alice", 25);
std::string name = myPair.first; // Access first element of the pair (O(1))
int age = myPair.second; // Access second element of the pair (O(1))
6. Set:
STLs 4
Insertion/Deletion/Lookup: O(log n) on average for ordered sets (e.g., std::set in C++), O(1) on
average for unordered sets (e.g., std::unordered_set in C++ with a good hash function).
#include <set>
std::set<int> mySet = {3, 1, 4, 1, 5, 9, 2, 6, 5};
mySet.insert(7); // Add unique elements (O(log n))
mySet.erase(4); // Remove element (O(log n))
bool containsFive = (mySet.find(5) != mySet.end()); // Check if an element exists (O(log n))
7. Map:
Insertion/Deletion/Lookup: O(log n) on average for ordered maps (e.g., std::map in C++), O(1) on
average for unordered maps (e.g., std::unordered_map in C++ with a good hash function).
#include <map>
std::map<std::string, int> myMap;
myMap["Alice"] = 25; // Associate values with keys (O(log n))
myMap["Bob"] = 30;
int aliceAge = myMap["Alice"]; // Retrieve value by key (O(log n))
#include <unordered_set>
std::unordered_set<int> myHashSet = {3, 1, 4, 1, 5, 9, 2, 6, 5};
myHashSet.insert(7); // Add unique elements (Amortized O(1))
myHashSet.erase(4); // Remove element (Amortized O(1))
bool containsFive = (myHashSet.find(5) != myHashSet.end()); // Check if an element exists (Amortized O(1))
#include <unordered_map>
std::unordered_map<std::string, int> myHashMap;
myHashMap["Alice"] = 25; // Associate values with keys (Amortized O(1))
myHashMap["Bob"] = 30;
int aliceAge = myHashMap["Alice"]; // Retrieve value by key (Amortized O(1))
10. Stack:
Push/Pop: O(1)
#include <stack>
std::stack<int> myStack;
myStack.push(1); // Push elements onto the stack (O(1))
myStack.push(2);
STLs 5
int topElement = myStack.top(); // Access the top element (O(1))
myStack.pop(); // Pop the top element (O(1))
11. Queue:
Enqueue/Dequeue: O(1)
#include <queue>
std::queue<int> myQueue;
myQueue.push(1); // Enqueue elements (O(1))
myQueue.push(2);
int frontElement = myQueue.front(); // Access the front element (O(1))
myQueue.pop(); // Dequeue the front element (O(1))
Insertion: O(log n)
#include <queue>
std::queue<int> myQueue;
myQueue.push(1); // Enqueue elements (O(1))
myQueue.push(2);
int frontElement = myQueue.front(); // Access the front element (O(1))
myQueue.pop(); // Dequeue the front element (O(1))
Keep in mind that these time complexities are generalized and can vary depending on the specific
implementation and language you are using. For example, the actual performance of hash-based data
structures like unordered sets and maps can be affected by the quality of the hash function and the load
factor. Additionally, some operations, like sorting, may not be mentioned in the above summaries but are
possible with some of these data structures.
Amortized time complexity is a way of analyzing the time cost of an algorithm or a data structure over
a sequence of operations. It considers the average time per operation over a series of operations
rather than focusing on the worst-case scenario for each operation.
In the context of data structures like vectors, deques, and unordered sets/maps, amortized time
complexity takes into account the cost of resizing or rehashing, which may be necessary to maintain
the data structure's properties or capacity. These resizing or rehashing operations can be relatively
expensive, but they don't occur with every insert or delete operation.
For example, in a vector, if the capacity is exceeded, a resizing operation may double the vector's
size. While this resizing operation has a time complexity of O(n), it doesn't happen with every
element insertion. Instead, it occurs periodically, and the cost is spread out over multiple insertions.
STLs 6
On average, the cost per insertion is much lower than O(n). This average cost per operation is what's
referred to as the amortized time complexity.
So, when we say that an operation on a data structure like a vector has an "amortized time
complexity of O(1)," we mean that, on average, the operation is relatively cheap, even though some
individual operations might be more expensive. It provides a more realistic view of the overall
performance of the data structure when used over a sequence of operations.
STLs 7