Dataslope logoDataslope

Algorithms Intuition

Thinking about cost — Big-O at the gut level, plus the standard algorithms you'll use every day.

You can write a program that produces the right answer and is still unusable because it takes hours when it should take milliseconds. Performance is a separate axis from correctness. Learning to feel how expensive an algorithm is — without doing formal proofs — is one of the most valuable software-engineering skills.

A working mental model of cost

For most everyday code, you care about a simple question: how many operations do I do as the input grows? That count is the algorithm's time complexity.

NotationPronouncedRough feel
O(1)"constant"Same time no matter the input size.
O(log n)"log n"Doubling n adds one step.
O(n)"linear"Doubling n doubles the work.
O(n log n)"n log n"Slightly worse than linear; the sweet spot for sorting.
O(n²)"n squared"Doubling n quadruples the work. Fine for n=1000, painful for n=100,000.
O(2ⁿ)"exponential"Adding one input element doubles the time. Only tractable for tiny n.

You don't need to be a theorist. Just learn to recognize the shape: nested loops over the same data are usually quadratic; a single pass is linear; halving the search space each step is logarithmic.

Counting in code

Code Block
C++ 20 (202002L)

For n=8 the difference is invisible. For n=10,000,000 the linear loop takes a moment; the quadratic loop is hopeless.

The standard algorithms

Most of the algorithms you'd want are already in <algorithm>. They're tested, fast, and read clearly. Reach for them before writing a loop.

Code Block
C++ 20 (202002L)

A few rules of thumb:

  • std::sort is O(n log n) — your default sorting tool.
  • std::find, std::count, std::accumulate are linear.
  • std::lower_bound, std::upper_bound, std::binary_search require a sorted range and are logarithmic.
  • Algorithms that produce output (std::copy, std::transform) generally match the size of the input.

Algorithmic thinking, step by step

Suppose you must check whether any two of n numbers sum to a target. Three approaches with very different costs:

ApproachCostIdea
Try every pairO(n²)Nested loops
Sort, then two pointersO(n log n)Sort once; walk from both ends
Hash setO(n) averageFor each x, check if target - x is in a set

The fastest is also the easiest to get wrong (hash collisions, edge cases). The point of these chapters is not to memorize "the best" algorithm — it's to recognize that multiple approaches exist and that the cost is a deliberate choice.

Premature optimization vs. algorithmic thinking

The famous quote "premature optimization is the root of all evil" is about micro-optimizations — tweaking individual instructions, caches, branch predictors. It does not mean "ignore complexity." Picking O(n²) when O(n log n) is one extra line of code is not optimization, it's negligence at scale.

The right discipline:

  1. Pick the right algorithmic shape from the start.
  2. Write the clearest possible code at that complexity.
  3. Measure. Only then optimize the hot spot.

Challenge

Challenge
C++ 20 (202002L)
Sort and median

Given a hard-coded vector of 7 integers, sort it ascending and print the median (middle element). Use std::sort. Expected output for {8, 1, 6, 4, 2, 9, 3} is 4.

Test your understanding

QuestionSelect one

Two nested loops, each iterating from 0 to n, that do constant work per pair — what is the time complexity?

O(n)

O(log n)

O(n²)

O(n log n)

QuestionSelect one

Why does std::lower_bound require a sorted range?

The compiler enforces it.

It does not; it works on any range.

It uses binary search internally; binary search is correct only if the elements are arranged in order.

It uses hashing.

Next: the containers that hold those algorithms' inputs — and their trade-offs.

On this page