C++ PROGRAMMING · 13 MIN STUDY

STL complexity and problem-solving patterns

Choose containers and algorithms by complexity and combine them to solve common coding problems.

Learning objectives

  • Compare complexity for common STL containers and algorithms.
  • Choose a container from the operations a problem needs.
  • Combine algorithms and containers for frequency counting and deduplication.
  • Explain why complexity is a design tool, not a guarantee of wall-clock speed.

Prerequisites: sequence and associative containers, iterators, sorting, and Big-O notation. Review STL containers, Maps and sets, and STL algorithms first.

Container complexity at a glance

ContainerAccess / lookupInsert / removeImportant note
vectorIndex O(1)Back amortized O(1); middle O(n)Contiguous storage and good locality
dequeIndex O(1)Both ends O(1)Not one contiguous block
listSearch O(n)Known iterator O(1)Extra links and weaker locality
map/setO(log n)O(log n)Keys remain ordered
unordered_mapAverage O(1), worst O(n)Average O(1), worst O(n)Hashing, no sorted order
priority_queueTop O(1)Push/pop O(log n)Only top priority is exposed

Algorithm complexity

AlgorithmTypical complexity
find, count_ifO(n)
sortO(n log n)
lower_bound on random-access iteratorsO(log n)
binary_search on forward iteratorsO(log n) comparisons; movement may be O(n)

Pattern 1: frequency counting

std::unordered_map<int, int> frequency;
for (int value : values) {
    ++frequency[value];
}

Average O(n) total time for n values, assuming average constant-time hash operations. Use map instead if you need keys printed in sorted order.

Pattern 2: sort and remove duplicates

std::sort(values.begin(), values.end());
auto new_end = std::unique(values.begin(), values.end());
values.erase(new_end, values.end());

Sorting costs O(n log n); unique then scans linearly. This removes consecutive duplicates, which is why sorting first matters. The erase call removes the unused tail.

Pattern 3: maintain top k values

A min-heap of size k can keep the largest k values seen so far. Push each value; if the heap grows beyond k, pop the smallest. This takes O(n log k) time and O(k) extra space. The heap's top is the smallest among the retained k values.

How to choose

  1. Write down the operations the problem needs.
  2. Estimate how often each operation happens.
  3. Choose a container that supports the expensive operations efficiently.
  4. Account for ordering, memory, iterator invalidation, and worst-case behavior.
  5. Measure performance only after correctness is established.

Common mistakes

  • Choosing a linked list just because one insertion operation is O(1), ignoring search.
  • Calling unordered_map O(1) without saying average case.
  • Ignoring the cost of shifting vector elements.
  • Using binary search before establishing sorted order.
  • Optimizing a tiny operation while overlooking an O(n²) loop.

Practice

  1. Choose a container for counting word frequencies.
  2. Choose a container for maintaining values in sorted order with frequent insertion.
  3. Explain the complexity of sorting then removing duplicates.
  4. Design an O(n log k) approach to find the k largest numbers.
Show solutions
  1. unordered_map<string,int> for average fast lookup; use map if sorted output is needed.
  2. map or set, depending on whether key-value pairs or unique values are needed.
  3. O(n log n) for sort plus O(n) for unique/erase work.
  4. Maintain a min-heap of size k; replace its top when a larger value arrives.

Summary

Choose STL tools by required operations and complexity. Combine containers and algorithms to express common patterns clearly, and state average-case versus worst-case assumptions.

References