Data Structures
Understanding these data structures is crucial for efficient algorithm design and problem-solving. Each structure has its strengths and ideal use cases.
Quick Reference
| Data Structure | Insert | Delete | Search | Space | Description | Important Notes |
|---|---|---|---|---|---|---|
| Array | \(O(1)\) or \(O(n)\) | \(O(n)\) | \(O(n)\) | \(O(n)\) | Contiguous memory locations | Fast access, fixed size (static arrays) |
| Dynamic Array | \(O(1)\) amortized | \(O(n)\) | \(O(n)\) | \(O(n)\) | Resizable array | Occasional \(O(n)\) insert due to resizing |
| Linked List | \(O(1)\) | \(O(1)\) | \(O(n)\) | \(O(n)\) | Chain of nodes | Efficient insertion/deletion, poor random access |
| Stack | \(O(1)\) | \(O(1)\) | \(O(n)\) | \(O(n)\) | LIFO structure | Constant time push/pop operations |
| Queue | \(O(1)\) | \(O(1)\) | \(O(n)\) | \(O(n)\) | FIFO structure | Constant time enqueue/dequeue operations |
| Hash Table | \(O(1)\) average | \(O(1)\) average | \(O(1)\) average | \(O(n)\) | Key-value pairs | Potential \(O(n)\) worst-case for collisions |
| Min/Max Heap | \(O(\log n)\) | \(O(\log n)\) | \(O(n)\) | \(O(n)\) | Tree-based structure | Efficient for priority queues |
| Binary Search Tree | \(O(\log n)\) average | \(O(\log n)\) average | \(O(\log n)\) average | \(O(n)\) | Ordered binary tree | Potential \(O(n)\) worst-case for unbalanced trees |
| Red-Black Tree | \(O(\log n)\) | \(O(\log n)\) | \(O(\log n)\) | \(O(n)\) | Self-balancing BST | Guaranteed \(O(\log n)\) operations |
| AVL Tree | \(O(\log n)\) | \(O(\log n)\) | \(O(\log n)\) | \(O(n)\) | Strictly balanced BST | More balanced than Red-Black, but costlier updates |
Array
- Pros: Fast access, cache-friendly
- Cons: Fixed size (for static arrays), expensive insertion/deletion
- Use when: Fast access is crucial, size is known and fixed
Dynamic Array (e.g., std::vector)
- Pros: Flexible size, still allows fast access
- Cons: Occasional costly resizing operations
- Use when: Size may vary, but random access is still important
Linked List (e.g., std::list)
- Types: Singly linked, doubly linked, circular
- Pros: Efficient insertion/deletion, dynamic size
- Cons: Poor random access, extra memory for pointers
- Use when: Frequent insertions/deletions, size is unknown or changes frequently
Stack (e.g., std::stack)
- LIFO (Last In, First Out) principle
- Operations: push, pop, top
- Use when: Need to track function calls, undo mechanisms, expression evaluation
Queue (e.g., std::queue)
- FIFO (First In, First Out) principle
- Operations: enqueue, dequeue, front
- Use when: Managing tasks, breadth-first search, buffering
Hash Table (e.g., std::unordered_map)
Also called a hash map, it stores key-value pairs based on the hash value of the key. A clever hashing algorithm can reduce the time complexity of certain problems.
- Pros: Very fast average-case operations
- Cons: Potential for collisions, may require resizing
- Use when: Fast lookups are crucial, keys are hashable
Heap (e.g., std::priority_queue)
A heap is a specialized tree-based data structure that satisfies the heap property. It is commonly used to implement priority queues, a data structure that returns the element with the highest (or lowest) priority.
- Types: Min-heap, max-heap
- Pros: Efficient for priority queue operations
- Cons: Not suitable for searching for arbitrary elements
- Use when: Need to repeatedly remove the smallest/largest element
Trees
A tree is a hierarchical data structure consisting of nodes connected by edges.
Binary Search Tree (BST)
- Pros: Maintains sorted order, efficient operations when balanced
- Cons: Can become unbalanced, leading to worst-case \(O(n)\) operations
- Use when: Need sorted data with fast insertions/deletions
Red-Black Tree
- Self-balancing BST
- Pros: Guarantees \(O(\log n)\) operations, less rigid balance than AVL trees
- Cons: Complex implementation
- Use when: Need guaranteed performance for a mix of operations
AVL (Adelson-Velsky and Landis) Tree
- Strictly balanced BST
- Pros: More rigidly balanced than Red-Black trees, faster lookups
- Cons: More rotations during insertion/deletion than Red-Black trees
- Use when: Lookups are more frequent than insertions/deletions
C++ STL Containers and Common Operations
| Container | Insert | Delete | Search | Notes |
|---|---|---|---|---|
| vector | \(O(1)\) amortized | \(O(n)\) | \(O(n)\) | Dynamic array implementation |
| list | \(O(1)\) | \(O(1)\) | \(O(n)\) | Doubly linked list |
| deque | \(O(1)\) amortized | \(O(n)\) | \(O(n)\) | Double-ended queue |
| set | \(O(\log n)\) | \(O(\log n)\) | \(O(\log n)\) | Red-Black Tree implementation |
| multiset | \(O(\log n)\) | \(O(\log n)\) | \(O(\log n)\) | Allows duplicates |
| map | \(O(\log n)\) | \(O(\log n)\) | \(O(\log n)\) | Red-Black Tree implementation |
| unordered_set | \(O(1)\) average | \(O(1)\) average | \(O(1)\) average | Hash table implementation |
| unordered_map | \(O(1)\) average | \(O(1)\) average | \(O(1)\) average | Hash table implementation |
| priority_queue | \(O(\log n)\) | \(O(\log n)\) | \(O(1)\) for max/min | Heap implementation |
| stack | \(O(1)\) | \(O(1)\) | N/A | Adapter container |
| queue | \(O(1)\) | \(O(1)\) | N/A | Adapter container |