Analysis of Algorithms
What Is an Algorithm?
The definition and five properties of an algorithm, how to write pseudocode, proving correctness with loop invariants, and the RAM model used to analyse running time.
An algorithm is a finite sequence of well-defined steps that takes some input and produces the correct output for every valid input. A program is an algorithm written in a particular language for a particular machine; the algorithm itself is the idea.
The five properties (Knuth)
| Property | Meaning |
|---|---|
| Input | zero or more quantities supplied from outside |
| Output | at least one quantity produced |
| Definiteness | every step is precise and unambiguous |
| Finiteness | it always terminates after a finite number of steps |
| Effectiveness | every step is basic enough to be carried out exactly, in finite time |
"Keep stirring until it tastes good" fails definiteness. A loop that may never end fails finiteness.
The design and analysis process
- Understand the problem — inputs, outputs, constraints, edge cases.
- Choose a design technique — brute force, divide and conquer, greedy, dynamic programming, backtracking …
- Write the algorithm — usually in pseudocode.
- Prove it correct for all inputs.
- Analyse its time and space as a function of the input size
n. - Implement and test.
Pseudocode
Pseudocode describes an algorithm without the noise of a real language:
INSERTION-SORT(A, n)
for j = 2 to n
key = A[j]
i = j - 1
while i > 0 and A[i] > key
A[i + 1] = A[i]
i = i - 1
A[i + 1] = key(Textbooks like CLRS index arrays from 1. Translate carefully to 0-based code.)
Proving correctness: loop invariants
A loop invariant is a statement that is true before every iteration of a loop. To prove an algorithm correct with one, show three things:
- Initialisation — it is true before the first iteration.
- Maintenance — if it is true before an iteration, it remains true before the next.
- Termination — when the loop ends, the invariant gives a useful property that shows the algorithm is correct.
For insertion sort, the invariant is: at the start of each iteration, the subarray A[1..j−1] holds the original first j−1 elements in sorted order. When the loop ends with j = n + 1, the whole array is sorted.
#include <iostream>
#include <vector>
#include <cassert>
#include <algorithm>
using namespace std;
void insertionSort(vector<int> &a) {
for (size_t j = 1; j < a.size(); j++) {
assert(is_sorted(a.begin(), a.begin() + j)); // the loop invariant, checked at run time
int key = a[j];
int i = (int)j - 1;
while (i >= 0 && a[i] > key) { a[i + 1] = a[i]; i--; }
a[i + 1] = key;
}
}
int main() {
vector<int> a = {31, 41, 59, 26, 41, 58};
insertionSort(a);
for (int x : a) cout << x << " ";
cout << "\nsorted: " << boolalpha << is_sorted(a.begin(), a.end()) << endl;
return 0;
}26 31 41 41 58 59 sorted: true
The RAM model
To analyse algorithms independently of hardware, we use the Random Access Machine model:
- Each simple operation (arithmetic, comparison, assignment, array access, function call) takes one unit of time.
- Memory access is constant time.
- Instructions run one after another (no parallelism).
The running time T(n) is the number of unit steps for an input of size n. For example, insertion sort does about n²/4 comparisons on average, so T(n) grows like n².
Why analyse at all?
Suppose computer A runs 10⁹ instructions/second and computer B only 10⁷ — 100 times slower. Sort 10 million numbers:
| Algorithm | Steps | Time | |
|---|---|---|---|
| Computer A | insertion sort, 2n² | 2 × 10¹⁴ | about 55 hours |
| Computer B | merge sort, 50 n log₂ n | about 1.2 × 10¹⁰ | about 20 minutes |
A better algorithm on a slow machine beats a worse algorithm on a fast machine by orders of magnitude. That is why this subject exists.
Test yourself
4 questions · pick an answer to check it instantly
- 1
Which property says every algorithm must stop?
Finiteness: it terminates after a finite number of steps for every valid input. - 2
Which three parts make up a loop-invariant proof?
Show it holds initially, is preserved by each iteration, and gives correctness at the end. - 3
In the RAM model, how long does one array access take?
The model treats basic operations, including memory access, as constant time. - 4
"Repeat until the answer looks right" violates which property?
The step is not precise; "looks right" is ambiguous.