Algorithm Search⌘K

Definitionintro

Space complexity

Also called memory complexity, working space.

The function giving the amount of memory an algorithm uses as a function of input size.

The space complexity of an algorithm is the function SS that maps each input size nn to the number of memory cells that the algorithm uses on inputs of size nn, in a stated model of computation. As for time complexity, the definition must name the case (worst, average) and say what is counted. The usual choice is the worst case, counted in machine words, with the space of the recursion stack included.

Definition

Fix a model, here the word RAM: memory is an array of cells, and each cell holds one word of ww bits, with w≥⌈lg⁡n⌉w \ge \lceil \lg n \rceil so that an index into the input fits in one word. Many texts write that a word has Θ(log⁡n)\Theta(\log n) bits. For an algorithm AA and an input xx, let sA(x)s_A(x) be the number of distinct cells that AA reads or writes during its run on xx. Then the worst-case space is

S(n)=max⁡x∈InsA(x),S(n) = \max_{x \in I_n} s_A(x),

where InI_n is the set of inputs of size nn. A cell that is allocated but never accessed is not counted. This is a convention. In practice an allocated array of kk words counts as kk words. The two measures agree for an algorithm that initializes all that it allocates.

Total and auxiliary space

Total space counts every cell that the run accesses, including the cells of the input. Auxiliary space (also called working space) counts only the cells outside the input and the output. The auxiliary space is the useful measure for an algorithm that reads an array of nn items, because the input already takes nn cells.

Most texts on algorithms use a second convention: the whole input always counts, so the total space is the size of the input plus the auxiliary space. This page counts accessed cells, as defined above. Under this rule a sublinear-time algorithm such as binary search accesses only O(log⁡n)O(\log n) cells of its input. An algorithm is in place when its auxiliary space is O(1)O(1) words. Some authors also call an algorithm in place when it uses O(log⁡n)O(\log n) auxiliary words, for example for a recursion stack.

The recursion stack counts

Each active call of a recursive function holds a frame: its parameters, its local variables and its return address. A frame of a function with a constant number of variables has O(1)O(1) words. So the stack space is O(d)O(d) words, where dd is the greatest number of active calls at one time. A recursive algorithm that holds no other memory has auxiliary space Θ(d)\Theta(d). Space is counted in words. In bits it is at most ww times larger. With the usual w=Θ(log⁡n)w = \Theta(\log n), an array of nn indices needs Θ(n)\Theta(n) words and Θ(nlog⁡n)\Theta(n \log n) bits. A mark array of nn bits needs only nn bits.

Time and space

Let each step of the machine access at most cc cells, where cc is a constant. A run of TT steps then accesses at most cTcT distinct cells. So S(n)≤c T(n)S(n) \le c \, T(n): the space is at most a constant times the time. This is why an algorithm that must touch each of nn cells has T(n)≥n/cT(n) \ge n/c. The converse is false. An nn-bit binary counter that counts from 00 to 2n−12^n - 1 uses nn bits and 2n−12^n - 1 increments. For a Turing machine that halts on each input, with a read-only input tape and S(n)≥log⁡nS(n) \ge \log n cells on the work tapes, the time is at most 2O(S(n))2^{O(S(n))}, because a configuration is described by O(S(n))O(S(n)) bits plus the head positions and the number of different configurations bounds the time (Arora and Barak, Chapter 4). On the Turing machine one counts the work tape only, which makes sublinear classes such as logarithmic space possible, and polynomial space is the class with S(n)=nO(1)S(n) = n^{O(1)}.

Examples and non-examples

Each entry is the auxiliary space in words for a sort of nn items or for a search.

  • Linear search, selection sort, insertion sort. A few indices and one temporary key. The space is Θ(1)\Theta(1).
  • Heapsort. The heap is built inside the input array, and a sift-down loop needs a constant number of words (two indices and one temporary key). The auxiliary space is O(1)O(1), so heapsort is in place in the strict sense.
  • Merge sort. The merge step writes into a second array. A version with an auxiliary array of nn items has Θ(n)\Theta(n) auxiliary space, and a version that copies only the left half before each merge needs ⌈n/2⌉\lceil n/2 \rceil items. The recursion has depth ⌈lg⁡n⌉\lceil \lg n \rceil, so it holds ⌈lg⁡n⌉+1\lceil \lg n \rceil + 1 frames. The total auxiliary space is Θ(n)\Theta(n), and the stack is of lower order.
  • Quicksort, stack space. After a partition, the algorithm calls itself on the smaller side and continues with the larger side in a loop. A call is made only on a range of at least 2 items. With this rule the stack never holds more than ⌊lg⁡n⌋\lfloor \lg n \rfloor frames, for n≥2n \ge 2. The partition must put the pivot in its final place and leave it out of both ranges. Proof: a call at depth dd (the first call has depth 00) starts with a range of sds_d items. At any time its frame works on a range of r≤sdr \le s_d items. A partition of this range leaves two ranges with r−1r - 1 items in total, so the child call gets at most (r−1)/2<sd/2(r-1)/2 < s_d/2 items, and sd+1≤sd/2s_{d+1} \le s_d/2. Since s0≤ns_0 \le n, we get sd≤n/2ds_d \le n/2^d. A call has sd≥2s_d \ge 2, so 2≤n/2d2 \le n/2^d and d≤lg⁡n−1d \le \lg n - 1. The number of frames is at most d+1≤lg⁡nd + 1 \le \lg n, and it is an integer. A version that recurses on both sides, with the last item as pivot, holds about nn frames on a sorted array, so its space is Θ(n)\Theta(n) in the worst case.
  • Binary search. The loop version uses O(1)O(1) words. The recursive version holds O(log⁡n)O(\log n) frames, unless the compiler removes tail calls.
  • Breadth-first search and depth-first search. A search of a graph with nn vertices and mm edges needs a mark for each vertex and a queue or a stack of at most nn vertices, when each vertex is marked as it is pushed (or when the depth-first search is recursive). Then the auxiliary space is Θ(n)\Theta(n). An iterative depth-first search that pushes every neighbor without a test of the mark can hold Θ(m)\Theta(m) entries.
  • Naive recursive Fibonacci. The function fib(n)=fib(n−1)+fib(n−2)\mathrm{fib}(n) = \mathrm{fib}(n-1) + \mathrm{fib}(n-2) makes calls to depth nn, so it holds nn frames, and its space is Θ(n)\Theta(n). Its time is exponential. This shows that space can be much smaller than time.
  • Non-example: a bound that omits the stack. The statement "recursive quicksort or recursive binary search uses O(1)O(1) extra space" is wrong once the stack is counted. Quicksort that recurses on the smaller side uses Θ(log⁡n)\Theta(\log n) words in the worst case. A bound that omits the stack is a bound on the heap memory only, and it should say so.
  • Non-example: cumulative allocation. A routine that allocates a new array of kk words in each of nn loop rounds and frees it at the end of the round has peak space O(k)O(k). The sum of all allocations is nknk words. Space is the peak use, not the sum.
  • Time complexity counts steps. Space and time are two separate costs, and many algorithms trade one for the other.
  • In-place algorithm: auxiliary space O(1)O(1), or O(log⁡n)O(\log n) in the weaker use.
  • Word RAM: the model with words of Θ(log⁡n)\Theta(\log n) bits in which space is counted in words.
  • Logarithmic space and polynomial space: the complexity classes that bound the space of a Turing machine.
  • Input size: the argument of SS.

References

  1. Cormen, Leiserson, Rivest and Stein, Introduction to Algorithms, fourth edition, Chapter 2 (Section 2.3, merge sort) and Chapter 7 (quicksort, stack depth)
  2. Donald E. Knuth, The Art of Computer Programming, Volume 3, second edition, Section 5.2.2 (sorting by exchanging, stack size of quicksort) and Section 5.2.3 (heapsort)
  3. Michael Sipser, Introduction to the Theory of Computation, third edition, Chapter 8 (Space Complexity)
  4. Sanjeev Arora and Boaz Barak, Computational Complexity: A Modern Approach, Chapter 4 (Space complexity)

About this page

The build computes these levels from the evidence in the repository. Each row says what the next level needs. Read what the levels mean.

LadderLevelWhat the next level needs
Human proofH0 no proof
  • add a proof in proofs/ (06.5)
LeanL0 no Lean part
  • name a Lean module in the lean field (07)
VisualV0 none
  • add viz/scene.ts or a figure (10)
WritingW4 complete
  • a review of the text: no review record reviews/RF1AVH/text.yaml