What pseudocode is, and what it is not
You already know from the earlier guide that an algorithm is a finite, unambiguous recipe for turning every valid input into the right output. Pseudocode is simply how we write that recipe down so a human can read it. It is not Python, not C, not any one language — it borrows the useful skeleton of programming (assignments, loops, if-tests, function calls) and throws away the fussy parts (semicolons, type declarations, import statements) that distract from the idea.
This freedom is the whole point. Because reading pseudocode is about meaning rather than syntax, the same loop might say `for i = 1 to n` in one book and `for each i in [1..n]` in another, and both mean the identical thing. Your job is never to compile it; your job is to understand what it computes. That is exactly the line drawn in the problem-vs-algorithm-vs-program distinction: pseudocode lives at the algorithm level — the idea — not at the program level, which is one concrete runnable encoding of that idea.
The five things every pseudocode is made of
Almost all the pseudocode you will ever meet is built from just five kinds of moves, and once you can name them, the fear evaporates. The first is sequence: do this, then that, top to bottom. The second is assignment: `x = 7` means store the value 7 in the box named x, and a later `x = x + 1` reads the old contents, adds one, and writes the result back into the same box.
The third is the conditional: `if condition then ... else ...` chooses one branch based on a yes/no test. The fourth is the loop: a `for` loop repeats a fixed number of times, while a `while` loop repeats as long as a condition stays true. The fifth is the call: invoking another named procedure, possibly itself (recursion), and using whatever it returns. Reading any program reduces to recognizing these five and asking, for each, exactly what it does to the values in the boxes.
LinearSearch(A, n, key):
for i = 1 to n:
if A[i] == key:
return i // found it at position i
return NOT_FOUND // fell off the endTrace it by hand — the one habit that conquers fear
The single most powerful reading technique is to trace: pick a tiny concrete input and play computer, writing down the value of every variable after every line. Crucially, you simulate against the RAM model from the cost-model guides — a machine where reading or writing one variable, comparing two numbers, or doing one arithmetic operation each counts as one basic step that takes constant time. So a trace is not vague hand-waving; it is you executing well-defined steps, one at a time, on paper.
- Pick a small input. For LinearSearch above, take A = [4, 8, 5], n = 3, key = 5.
- Enter the loop with i = 1: test A[1] == key, i.e. 4 == 5? No. So we do not return; the loop advances.
- Now i = 2: test 8 == 5? No again. Advance once more.
- Now i = 3: test 5 == 5? Yes — execute `return i`, handing back 3, and the algorithm stops.
- Sanity-check the output against the problem: position 3 really does hold the key. The trace and the spec agree, which is the first sign the code is right.
Notice what the trace also reveals: on this input the loop body ran three times. Tracing is therefore the doorway to analysis — once you see how many times a body runs, you are already counting loop iterations, the raw material of a running-time count. A single trace does not prove anything in general (it is one input, not all of them), but it makes the mechanism vivid, and vivid mechanisms are easy to reason about.
Reading loops: the invariant lens
Tracing one input convinces you a loop works once. To understand why it always works, look at it through the lens of a loop invariant — a statement that is true every time the loop is about to check its condition, no matter the input. For LinearSearch the invariant is: "key does not appear anywhere in positions 1 through i-1." Before the loop starts that range is empty, so it holds trivially; each iteration that fails to return preserves it by adding one more checked-and-absent position.
This invariant idea is not a side trick; it is the standard way to read and trust loops, and a full guide later in this ladder is devoted to turning it into airtight proofs. For now, just practice the reading move: whenever you meet a loop, pause and ask, "what is true at the top of every pass?" That one question turns an intimidating block of repetition into a single calm sentence you can hold in your head.
Honest cautions before you trust any snippet
Pseudocode's freedom has a price: because it is not run by a compiler, nothing forces it to be complete or even correct. A snippet may quietly assume the array is non-empty, that indices start at 1, that `key` has a sensible type, or that some helper does exactly what its name suggests. Good pseudocode states these assumptions; sloppy pseudocode leaves them as traps. Reading without fear does not mean reading without skepticism — it means knowing what to check.
Two boundary questions catch most bugs. First, the edges: what happens on the empty input, on n = 0, on the very first and very last index? Trace those explicitly — off-by-one errors hide there. Second, termination: every loop must eventually stop. A `for i = 1 to n` is safe because i marches toward n, but a `while` loop only terminates if some quantity provably shrinks toward a stopping point. If you cannot name what shrinks, you cannot yet trust the loop.
Finally, remember the scale you are reading at. The size of the input — the input size n — is what every later cost claim will be measured against, so as you read, keep asking "what is n here, and how does the work grow as n grows?" That habit quietly bridges this ground-floor reading skill to everything ahead: the cost model that counts steps, and the worst/average/best-case lenses that ask which inputs make the count large. Pseudocode is just the map; tracing, invariants, edges, and termination are how you learn to actually walk it.