Save the root, move the last active entry to the root, shrink the active prefix, then restore heap order by heapify down:Only edges descending from the moved entry can violate heap order. If the entry is no larger than every child, the entire heap is valid. Otherwise swapping with a minimum child restores the order at the old position: that child is no larger than the old entry or any sibling. Its original subtree was already ordered, so only the moved entry's new outgoing edges can remain invalid. This is the loop invariant of
ExtractMin(A):
if A.heap_size == 0:
error "empty heap"
answer = A[0]
A[0] = A[A.heap_size-1]
A.heap_size = A.heap_size-1
if A.heap_size > 0:
SiftDown(A,0)
return answer
SiftDown(A,i):
while true:
best = i
for j = 0,...,d-1:
c = Child(i,j)
if c >= A.heap_size:
break
if A[c] < A[best]:
best = c
if best == i:
return
swap A[i], A[best]
i = bestSiftDown. Each swap moves it down one level, proving termination and correctness.For , the height is , and selecting a minimum child costs at most comparisons per level. Thus
ExtractMin takes time, with auxiliary storage. Empty and singleton heaps take constant time. For , there is at most one nonroot level and the loop examines at most actual children, taking ; this also lies within for . The coarser uniform expression safely includes all small sizes.Use two array indices, advancing only the smaller current entry. Here and in Questions 1–4, code is structured Oberon-style pseudocode: Let be the smallest common value, and let . Existence implies . A useful loop invariant is , , with no common value among the discarded prefixes and . Initially the prefixes are empty. If , then cannot equal any entry of because that sorted array is increasing; it cannot be a common value in the discarded prefix either. Moreover would imply , a contradiction. Thus and incrementing is safe. The other branch is symmetric.
RETURN exits a procedure, Some(x) and None distinguish success and absence, and AND short-circuits from left to right. Arithmetic is exact where the source asks us to ignore integer overflow.PROCEDURE common(a, N, b, M): INTEGER;
VAR i, j: INTEGER;
BEGIN
i := 0; j := 0;
WHILE a[i] # b[j] DO
IF a[i] < b[j] THEN i := i + 1
ELSE j := j + 1
END
END;
RETURN a[i]
END common;Every guard and return therefore uses valid array indices, even without explicit bounds tests. The loop variant decreases on each iteration. At exit the equal entries form a common value no larger than , hence equal . There are at most increments and constant work per increment. The procedure returns the smallest common value in time and auxiliary space.
Replace the existence-dependent bounds proof with explicit bounds tests. Neither input array is changed or copied.The loop invariant is , , and every common value of the original arrays lies in both remaining suffixes and . Equivalently neither discarded prefix contains a common value. Advancing the smaller current value preserves this for the same ordering reason as in part (a).
PROCEDURE commonOrNone(a, N, b, M);
VAR i, j: INTEGER;
BEGIN
i := 0; j := 0;
WHILE (i < N) AND (j < M) DO
IF a[i] = b[j] THEN RETURN Some(a[i])
ELSIF a[i] < b[j] THEN i := i + 1
ELSE j := j + 1
END
END;
RETURN None
END commonOrNone;Both array bounds are checked before any element is read. If the remaining heads are equal, all later entries are larger, so the returned value is the smallest. If either suffix becomes empty, the loop invariant proves there is no common value. The loop variant decreases on each unsuccessful comparison. The result is
Some(smallest common value) or None, with time and auxiliary space, including empty-input cases. A language without short-circuit operators can use nested tests; the guard here itself contains no array reads.The cyclic strict comparisons in the hint identify a head that cannot be the answer:Let be the smallest common value. The loop invariant is , , , and every discarded entry is not common to all three arrays. If , the entry cannot occur in the unprocessed part of , so discard it. The branch has the analogous justification. If neither comparison holds but the heads are not all equal, the hint guarantees , so discard .
PROCEDURE common3(a, N, b, M, c, L): INTEGER;
VAR i, j, k: INTEGER;
BEGIN
i := 0; j := 0; k := 0;
WHILE (a[i] # b[j]) OR (b[j] # c[k]) DO
IF a[i] < b[j] THEN i := i + 1
ELSIF b[j] < c[k] THEN j := j + 1
ELSE k := k + 1
END
END;
RETURN a[i]
END common3;A pointer at its target position cannot be advanced: for example and would imply . Thus all reads stay within array bounds. The loop variant decreases. At exit all heads equal . The cost is time and auxiliary space.
Maintain one array index per input and a candidate value. Cycle through the arrays, counting consecutive agreements with that candidate; when a larger head is encountered, start counting agreements again. The loop invariant has three parts. All indices satisfy ; no discarded entry is common to every input; and every original common value is at least
p is an auxiliary array of indices, not a copy of any input.PROCEDURE commonMany(as, n, m);
VAR p: ARRAY m OF INTEGER;
j, candidate, agree, x: INTEGER;
BEGIN
FOR j := 0 TO m-1 DO
p[j] := 0;
IF n[j] = 0 THEN RETURN None END
END;
candidate := as[0][0];
j := 0; agree := 0;
WHILE agree < m DO
IF p[j] = n[j] THEN RETURN None END;
x := as[j][p[j]];
IF x < candidate THEN
p[j] := p[j] + 1
ELSIF x = candidate THEN
agree := agree + 1;
j := (j + 1) MOD m
ELSE
candidate := x;
agree := 1;
j := (j + 1) MOD m
END
END;
RETURN Some(candidate)
END commonMany;candidate. Additionally, the agree cyclically consecutive arrays immediately preceding index j have heads equal to candidate. These facts are true initially, with an empty agreement run.A head below
candidate is not globally common, by the lower-bound clause, so advancing its pointer is safe. A head above candidate gives a new lower bound: every globally common value lies in this array's unprocessed suffix and so is at least its head. Only this array is yet certified to agree with the new candidate. An equal head extends the run by one. An exhausted suffix proves absence; a run of agreements covers every array exactly once and proves that candidate is common, and the lower-bound clause proves minimality. The exhaustion test precedes each dereference, including after the last entry of a suffix is discarded.For algorithm termination and time complexity, charge comparisons to the pair
(j,p[j]). A fixed entry is discarded at most once, can raise the candidate at most once, and can be counted as an agreement at most once: before the same array is revisited, either the algorithm has finished or the candidate has strictly increased. Thus there are at most three comparisons per input entry, besides the initialization. The result is the smallest common value or None in time and auxiliary space. For , the first head immediately gives the answer.Evaluate the supplied function once at each positive integer, retaining its largest value so far. In particular do not initialize the maximum to zero: might be negative everywhere.At the loop head the loop invariant is ,
PROCEDURE record(f, emit);
VAR n, best, y: INTEGER;
BEGIN
best := f(1);
emit(1);
n := 2;
WHILE TRUE DO
y := f(n);
IF y > best THEN
emit(n);
best := y
END;
n := n + 1
END
END record;best , and precisely the record values with argument less than have been emitted, in increasing argument order. The first argument is a record because its comparison set is empty. The strict test correctly excludes ties. Updating best only on a strict increase preserves the loop invariant.Exactly one call of
f is made per processed argument. For an arbitrary supplied function, an unexamined argument can have a value larger than all previous values, so skipping its evaluation cannot be correct in general. This assumes is a total, deterministic function; the requested infinite computation ignores integer overflow.Test each possible positive divisor directly:For , the loop invariant is and
PROCEDURE divisors(n: INTEGER): INTEGER;
VAR i, count: INTEGER;
BEGIN
i := 1; count := 0;
WHILE i <= n DO
IF n MOD i = 0 THEN count := count + 1 END;
i := i + 1
END;
RETURN count
END divisors;count . Testing adds exactly the next possible divisor. The loop variant decreases, and the divisor in MOD is always positive. At exit the interval contains every positive divisor. This computes the divisor function using remainder operations, time, and auxiliary space.Use trial division on a shrinking residual. Once the trial divisor exceeds its square root, any residual larger than one is itself prime.For the outer loop invariant, let be the set of primes below
PROCEDURE divisors(n: INTEGER): INTEGER;
VAR residual, trial, exponent, answer: INTEGER;
BEGIN
residual := n; trial := 2; answer := 1;
WHILE trial * trial <= residual DO
exponent := 0;
WHILE residual MOD trial = 0 DO
residual := residual DIV trial;
exponent := exponent + 1
END;
answer := answer * (exponent + 1);
trial := trial + 1
END;
IF residual > 1 THEN answer := 2 * answer END;
RETURN answer
END divisors;trial and their exponents in the original . Thenand residual has no prime factor below trial. If trial divides the residual it must therefore be prime: a composite trial value would have a smaller prime factor, contradicting this clause. If it does not divide, the zero exponent contributes the factor .For the inner loop invariant, let be the residual on entry. Then . Each exact division reduces the positive residual by at least a factor of two, so this loop terminates. At exit the exponent is the full multiplicity of
trial; multiplying by exponent+1 preserves the outer loop invariant. The outer loop terminates because trial increases and residual never increases. When it exits, a composite residual would have a prime factor at most its square root, yet every smaller trial factor has already been excluded. Hence the residual is or a single remaining prime of exponent .The procedure computes in unit-cost time and auxiliary space, with the separate successful divisions bounded by . No array or table of primes is needed, and correctly returns .
Print a prefix while following the linked list, counting how many closing parentheses remain. The final reciprocal can be printed without parentheses.The first loop invariant says that
PROCEDURE printCF(f: fraction);
VAR p: fraction; opened: INTEGER;
BEGIN
p := f; opened := 0;
Out.Int(p.head, 0);
p := p.tail;
WHILE p # NIL DO
IF p.tail = NIL THEN
Out.String("+1/"); Out.Int(p.head, 0)
ELSE
Out.String("+1/("); Out.Int(p.head, 0);
opened := opened + 1
END;
p := p.tail
END;
WHILE opened > 0 DO
Out.String(")"); opened := opened - 1
END
END printCF;p is the next unprinted linked list node, the printed text is the correct expression prefix, and opened counts its unmatched opening parentheses. The final node contributes no opening parenthesis; the second loop invariant says that precisely opened closing parentheses remain. Thus [1,2,3,4,5] produces 1+1/(2+1/(3+1/(4+1/5))). A singleton prints just its head. If the first head is negative, its leading minus remains a valid prefix; subsequent heads are positive.The precondition is a finite nonempty continued fraction list. Every dereference is made only for a nonnull pointer. The procedure uses auxiliary space and time linear in the number of nodes, apart from printing their digits. The source's claimed strict upper bound has an exception under its stated definition:
[x0,1] represents . None of these algorithms relies on that incorrect strict bound.Accumulate the product of the matrices from left to right, which matches forward linked list traversal.The four-value assignment is simultaneous, as permitted by the source. With , the loop invariant after reading the prefix iswith the empty product initialized to the identity matrix. Multiplication on the right by produces exactly the four assignments above. The associativity of matrix multiplication allows this left-to-right accumulation even though the recursive conversion groups operations from the right.
PROCEDURE cf2rat(f: fraction; VAR n, d: INTEGER);
VAR p: fraction; a, b, c, e, x: INTEGER;
BEGIN
a := 1; b := 0; c := 0; e := 1;
p := f;
WHILE p # NIL DO
x := p.head;
a, b, c, e := a*x+b, a, c*x+e, c;
p := p.tail
END;
n := a; d := c
END cf2rat;At completion, the first column is the numerator/denominator pair for the whole continued fraction: the last factor sends to , and each earlier factor applies the recurrence from part (d). The vector is an algebraic device, not a finite input ratio requiring division by zero. For a nonempty list the resulting is positive; for a singleton it is . The product has determinant , so its first-column entries are coprime. Return in linear node-processing time and auxiliary space, without changing the list.
Assume every indicated segment lies within array bounds, and lengths are nonnegative. Use a temporary value of element type The first procedure even works for . For the second, disjointness ensures that each swap exchanges the two original entries at offset
T:PROCEDURE swap(i, j: INTEGER);
VAR x: T;
BEGIN
x := m[i]; m[i] := m[j]; m[j] := x
END swap;
PROCEDURE blockswap(i, j, n: INTEGER);
VAR t: INTEGER;
BEGIN
t := 0;
WHILE t < n DO
swap(i+t, j+t);
t := t + 1
END
END blockswap;t without disturbing any other pair. Its loop invariant says that offsets below t have been exchanged, offsets from t through retain their original values, and everything outside the two segments is unchanged. The loop variant proves algorithm termination. A block exchange uses swaps and auxiliary space. The stray wp printed after this source subpart is not an additional requirement.Exchange symmetric pairs, stopping before the middle:Writing for the pre-call array, the loop invariant says that the first and last
PROCEDURE reverse(i, n: INTEGER);
VAR t: INTEGER;
BEGIN
t := 0;
WHILE t < n DIV 2 DO
swap(i+t, i+n-1-t);
t := t + 1
END
END reverse;t positions of the segment already satisfy , all positions between them retain their original values, and positions outside the segment are unchanged. Each swap fixes the next symmetric pair. The loop variant decreases; the two indices are distinct and in bounds whenever the body executes. Exactly swaps reverse the segment, with the odd-length middle element left in place and no accesses for .Replace the sole recursive call by updates to the current segment's parameters:The loop invariant is that every position outside the current unresolved segment already has its final value, while rotating the current segment by the current
PROCEDURE rotate(i, n, k: INTEGER);
VAR a, b: INTEGER;
BEGIN
WHILE (k > 0) AND (k < n) DO
a := n-k; b := k;
IF a = b THEN
blockswap(i, i+a, a);
RETURN
ELSIF a < b THEN
blockswap(i, i+b, a);
n := b; k := b-a
ELSE
blockswap(i, i+a, b);
i := i+b; n := a; k := b
END
END
END rotate;k completes the original array rotation. The block decompositions in part (ii) prove preservation. The positive unresolved length decreases in each continuing branch; the equal-block branch finishes immediately. The same rotation now uses auxiliary space, including control storage, and leaves the rest of the array untouched.Save the last entry, shift the others right in descending index order, and put the saved value at the left. Descending order prevents overwriting an unread entry.For one pass, after the shifts at offsets greater than
PROCEDURE rotate(i, n, k: INTEGER);
VAR x: T; step, t: INTEGER;
BEGIN
IF (k = 0) OR (k = n) THEN RETURN END;
step := 0;
WHILE step < k DO
x := m[i+n-1];
t := n-1;
WHILE t > 0 DO
m[i+t] := m[i+t-1];
t := t-1
END;
m[i] := x;
step := step+1
END
END rotate;t, those positions contain the original preceding entries; offsets through t are still available, and x retains the original last entry. The loop variant t decreases to zero. The outer loop invariant is that the segment has been rotated right by step places relative to its initial state. Repeating a one-step cyclic permutation times therefore gives the required array rotation. The method uses one extra T variable and time, with auxiliary space. The early return avoids all accesses for an identity rotation.Keep both the exponent and its power. This Oberon procedure uses only the permitted arithmetic:The loop invariant is and . It holds initially because . A successful guard permits the next power, and the two assignments preserve the relation between and . At exit, , which is exactly part (a). Each iteration increases , and only finitely many powers of are at most , proving algorithm termination. The returned value is . Its running time is arithmetic operations; integer overflow is deferred to part (e).
PROCEDURE IntLog(b, n: INTEGER): INTEGER;
VAR i, p: INTEGER;
BEGIN
i := 0; p := 1;
WHILE p*b <= n DO
p := p*b; i := i+1
END;
RETURN i
END IntLog;Use repeated squaring, including index zero:The loop invariant is for , with for every stored entry except possibly the initial entry when . Squaring gives , proving preservation. The first failed guard identifies the first larger power outside the range. If , no power with needs storing.
b2[0] := b; top := 0;
WHILE b2[top]*b2[top] <= n DO
b2[top+1] := b2[top]*b2[top];
top := top+1
END;Index zero is deliberately included. The original paper asks for indices but then claims that their products represent every allowable power. Taken without , that claim fails for odd exponents, since every available exponent would be even. The extra initialized entry makes the intended binary expansion argument valid without changing the requested entries.
Let be the largest representable positive integer. The worst case is , requiring indices through . Thus
enough = 5 for signed 32-bit integers, or 6 for signed 64-bit integers, suffices for stored powers that fit; a larger convenient constant is harmless. This counts slots starting at zero and does not reserve a slot for an out-of-range sentinel. The multiplication in the guard can still suffer integer overflow, independently of this array capacity bound.Store a second array For the second loop, write . Immediately before processing , its loop invariant isInitially the failed squaring guard gives ; this also holds when , since then . The test succeeds exactly when . If successful, adding selects that binary digit; otherwise the upper bound tightens to . Either way the invariant holds for the next smaller . At , , so
weight with weight[k] = 2^k. Descending through the binary digits of the answer gives this greedy algorithm:PROCEDURE FastLog(b, n: INTEGER): INTEGER;
VAR b2, weight: ARRAY enough OF INTEGER;
top, k, i, p: INTEGER;
BEGIN
b2[0] := b; weight[0] := 1; top := 0;
WHILE b2[top]*b2[top] <= n DO
b2[top+1] := b2[top]*b2[top];
weight[top+1] := weight[top]+weight[top];
top := top+1
END;
i := 0; p := 1; k := top;
WHILE k >= 0 DO
IF p*b2[k] <= n THEN
p := p*b2[k]; i := i+weight[k]
END;
k := k-1
END;
RETURN i
END FastLog;i = L.There are squarings and descending tests. For fixed , this is arithmetic operations, hence logarithmic in the bit length of , and also within the weaker bound. This counts arithmetic operations on integers as unit cost; bit complexity would also charge for the growing operands. No division is used.
Write parts in nonincreasing order. The array The recursion invariant is that
part stores the current prefix, and Emit(i,r,len) completes it using parts at most with remaining sum . With Out as the Oberon output module:VAR part: ARRAY MaxParts OF INTEGER;
PROCEDURE Emit(i, r, len: INTEGER);
VAR j: INTEGER;
BEGIN
IF r = 0 THEN
j := 0;
WHILE j < len DO
IF j > 0 THEN Out.Char("+") END;
Out.Int(part[j], 0); j := j+1
END;
Out.Ln
ELSIF i > 0 THEN
IF i <= r THEN
part[len] := i;
Emit(i, r-i, len+1)
END;
Emit(i-1, r, len)
END
END Emit;
PROCEDURE PrintPartitions(n: INTEGER);
BEGIN
Emit(n, n, 0)
END PrintPartitions;part[0..len) is nonincreasing, has sum , and every further part must be at most and at most the last existing part. The first branch includes the next part ; the second excludes it. These alternatives partition all completions, so each integer partition is printed exactly once. A recursive call reduces ; the printing loop's loop invariant is that the first entries have been printed with exactly the necessary separators.For , no partition has more than parts, and the all-ones partition has exactly . Thus the fixed array requires to handle every partition. When a write occurs, and therefore
len < n, so this bound prevents an out-of-range write. Zero prints one empty line, representing the empty integer partition. Available call stack space imposes a further practical limit.Use dynamic programming in increasing order of the maximum permitted part and then of the remaining sum. Let Require . The outer loop invariant says all rows below equal . The inner loop invariant additionally says entries before column in the current row are correct. Its dependencies are the previous row and the earlier column , so no future entry is read. Each state is evaluated once, giving arithmetic operations and stored counts. A memoization table around part (a)'s recursion is another valid way to share states; its entries need a separate “computed” flag because zero is a legitimate answer. Growing count sizes affect bit complexity and can cause integer overflow in a fixed-width
Count be a sufficiently wide integer type and let table have dimensions (MaxN+1) by (MaxN+1):PROCEDURE CountPartitions(n: INTEGER): Count;
VAR i, j: INTEGER;
table: ARRAY MaxN+1, MaxN+1 OF Count;
BEGIN
table[0,0] := 1; j := 1;
WHILE j <= n DO table[0,j] := 0; j := j+1 END;
i := 1;
WHILE i <= n DO
table[i,0] := 1; j := 1;
WHILE j <= n DO
table[i,j] := table[i-1,j];
IF j >= i THEN
table[i,j] := table[i,j] + table[i,j-i]
END;
j := j+1
END;
i := i+1
END;
RETURN table[n,n]
END CountPartitions;Count.Perform a depth-first traversal, retaining the path's letters in a buffer. A terminal node must be printed before its children, so a word precedes its proper extensions in lexicographic order.The recursion invariant is that
VAR word: ARRAY N OF CHAR;
PROCEDURE Visit(t: Trie; depth: INTEGER);
VAR j, c: INTEGER;
BEGIN
IF t # NIL THEN
IF t.terminal THEN
j := 0;
WHILE j < depth DO
Out.Char(word[j]); j := j+1
END;
Out.Ln
END;
c := 0;
WHILE c < 26 DO
IF t.child[c] # NIL THEN
word[depth] := CHR(ORD("a")+c);
Visit(t.child[c], depth+1)
END;
c := c+1
END
END
END Visit;
PROCEDURE PrintTrie(t: Trie);
BEGIN
Visit(t, 0)
END PrintTrie;word[0..depth) spells the path to t. The child loop's loop invariant says children with indices below c have been completely printed. Each edge appends its lowercase label; each terminal flag prints exactly one represented string. All words therefore appear once, in lowercase. The output loop prints precisely the prefix of length depth; no terminating zero needs storing in this buffer.An
N-character buffer suffices for words of length at most N. At depth N there can be no child, so word[N] is never accessed. A terminal root prints an empty line; a NIL root prints nothing. The running time is linear in allocated nodes plus the number of printed characters, since the alphabet size is fixed at 26.