3.1.4 · D4Complexity Analysis

Exercises — Space complexity — auxiliary vs total

2,966 words13 min readBack to topic

Before we start, one picture to fix the vocabulary so no symbol sneaks in undefined.

Figure — Space complexity — auxiliary vs total
Figure 1 — The cream box (left) is the INPUT the caller handed you: five fixed cells you cannot shrink. The orange tray (right) is the AUXILIARY scratch you allocate yourself — smaller is cleverer. The plum bracket underneath spans both: TOTAL = everything held on the table at once.

The cream box on the left is the input the caller handed you — you did not choose its size, so you cannot make it smaller. The orange tray on the right is scratch you allocated. Auxiliary counts only the orange tray. Total counts the whole table.


Level 1 — Recognition

(You just apply a rule of thumb. No tricks.)

Recall Solution 1.1

WHAT we count: the number of memory cells the function holds at peak. The cells: 7 scalar integers. That is a fixed number — it does not grow when (the input length) grows. WHY : Big-O throws away constant factors. "7 cells always" behaves like "1 cell always" as . Both are flat lines. Answer: .

Recall Solution 1.2

Auxiliary: you allocated a list whose length is proportional to ⇒ one cell per element ⇒ . Total: input list plus the copy . Adding, (constants drop). Answer: auxiliary , total .

Recall Solution 1.3

Count the cells: rows, each holding numbers ⇒ cells alive at once. WHY : the raw count is (there is no constant multiplier to drop here — one cell per grid square). Big-O keeps the dominant growing term, and grows faster than any lower power of , so the answer is . Had we allocated, say, cells, Big-O would still drop the constant and report — the same constant-dropping rule as Exercise 1.1. Answer: .


Level 2 — Application

(Read short code, count peak cells yourself.)

Recall Solution 2.1

Worst case is "all elements distinct." Then seen ends up holding all elements, and out holds all too. Peak cells: . Answer: auxiliary. (Input is also , so total is as well.)

Recall Solution 2.2

The tempting answer: "there's an array, so ." The real count: the array freq always has exactly 26 slots, no matter how long the string is. 26 does not grow with . WHY : a fixed-size container is a constant number of cells, so it is — the same reasoning as 7 scalars in Exercise 1.1. Answer: auxiliary.

Recall Solution 2.3

Count what out holds at peak: the double loop runs times, and each iteration appends one number. So out grows to cells. Careful: the time is and the space is also here — but only because we store every product. If we merely summed them, space would be . Answer: auxiliary.


Level 3 — Analysis

(Recursion enters. You must find the peak stack depth.)

Recursion is the sneaky part, so here is the picture the whole level rests on.

Figure — Space complexity — auxiliary vs total
Figure 2 — A chain of recursive calls to rec_sum. Each rounded box is one live stack frame. The orange double-arrow on the left measures the peak depth ; the plum note on the right says all frames are frozen and waiting at the same instant, so the stack space is .

Each pending call keeps its own stack frame (a little box of its local variables) alive until it returns. The picture shows a chain of calls: while the deepest one is still running, all the shallower ones are frozen and waiting — they all occupy memory at the same time. So auxiliary stack space = maximum depth reached × (space per frame). This is exactly the idea from Recursion and the call stack.

Recall Solution 3.1

How deep does it go? Each call increases i by 1 until i == n. So the chain is calls long before the first return 0 fires. Peak frames alive: frames stacked at once ⇒ stack. Answer: auxiliary — even though the function returns a single number and declares almost nothing.

Recall Solution 3.2

The trap: the time is (exponentially many calls), so people write for space too. The truth: space = peak simultaneous frames, not total calls. The calls happen mostly one-after-another and return before their siblings start. At any instant, the deepest live chain is fib(n) → fib(n-1) → fib(n-2) → ... → fib(1), which is depth . Answer: auxiliary. (Time , space — different resources, different answers.)

Recall Solution 3.3

How deep before hitting size 1? Starting at and halving: . The number of halvings to reach 1 is the exponent with , i.e. . WHY logarithm and not : we don't subtract 1 each time (that gives depth ); we divide by 2, and repeated division is measured by . That is precisely why balanced divide-and-conquer stacks are so shallow. Answer: auxiliary (stack), balanced case.


Level 4 — Synthesis

(Combine input, aux, recursion, and compare designs.)

Recall Solution 4.1

(a) Temp array: merging needs a scratch buffer as big as the part being merged; at the top level that is . (b) Recursion stack: halving each level ⇒ depth (each frame holds a few scalars). (c) Combined: peak auxiliary is the sum, . Since dominates for large , this simplifies to . Answer: (a) , (b) , (c) .

Recall Solution 4.2

No temp array ⇒ the only auxiliary is the recursion stack. (a) Balanced: each partition splits roughly in half ⇒ depth . (b) Worst case: a bad pivot peels off just one element per call, so the chain is n → n-1 → n-2 → ... → 1, depth stack. Answer: (a) , (b) . WHY the gap: balanced recursion divides (log depth); degenerate recursion subtracts one (linear depth) — exactly the contrast from Exercises 3.1 and 3.3.

Recall Solution 4.3

A's cells: . B's cells: . Since , we get exactly. Ratio: . Answer: about 52,000× more auxiliary memory for A. Same time class, wildly different memory — the whole reason Quick Sort is often preferred over Merge Sort when memory is tight.


Level 5 — Mastery

(Novel situations, you derive the answer with no template.)

Recall Solution 5.1

How many subsets? Each of the elements is either in or out — choices each — giving subsets. How big is each? A subset can be up to elements long. Total stored cells: (number of subsets) × (size each) . Answer: auxiliary. Contrast: if we only processed each subset one at a time and threw it away, auxiliary would collapse to the recursion depth — the storing is what makes it exponential.

Recall Solution 5.2

Balanced: the longest root-to-leaf path is the tree's height. A balanced tree of nodes has height (each level doubles the node count). Only one such path is alive at a time (siblings finish first). Answer (balanced): . Skewed (chain): height equals (a straight line of nodes) ⇒ . WHY: stack depth = tree height, and height ranges from (balanced) to (chain) — the same "divide vs subtract-one" story as Quick Sort in Exercise 4.2.

Recall Solution 5.3

Design A (recursive): recursion goes as deep as the list is long — frames alive at the peak ⇒ auxiliary stack. Design B (iterative, 3 pointers): exactly three scalar pointers, no matter how long the list ⇒ auxiliary. Better: Design B, because it turns hidden stack cost into constant memory — an in-place rewrite. The lesson: recursion's elegance can secretly cost space (Exercise 3.1); an iterative accumulator often reclaims it.

Recall Solution 5.4

Set up: the algorithm holds cells, and we want that to equal one billion, so . Solve: . Split the exponent: , and , so . Check: ✓. Answer: . Concluding remark: a quadratic table blows past a billion cells at only about thirty thousand elements — a tiny input by modern standards. That is exactly why an space algorithm is dangerous long before the machine feels slow: it runs out of memory well before it runs out of time, which is a concrete reason to prefer linear or logarithmic auxiliary designs whenever you can.


Connections

  • Parent: Space complexity — auxiliary vs total
  • Recursion and the call stack — where hidden stack space comes from (L3, L5).
  • Merge Sort / Quick Sort — the L4 space trade-off in the wild.
  • In-place algorithms — turning into (L5.3).
  • Asymptotic notation — Big-O, Big-Omega, Big-Theta — dropping constants and dominated terms.
  • Time complexity — Big-O notation — the resource we keep contrasting against.