Algorithm Search⌘K

Proofs: Sequential search symbol table

These are the human proofs of Sequential search symbol table, at full length.

The sequential search symbol table returns the stored values and keeps its invariant full

This proof shows: correctness, termination.

Statement. Let TT satisfy (I1) to (I3) for a map MM with n=T.nn = T.n keys. Then GET, PUT and DELETE stop, and:

  • GET(T,k)(T, k) returns M(k)M(k) if k∈Mk \in M and nil otherwise, and changes nothing;
  • after PUT(T,k,v)(T, k, v), (I1) to (I3) hold for the map M[k↦v]M[k \mapsto v];
  • after DELETE(T,k)(T, k), (I1) to (I3) hold for the map MM without kk.

Setup. By (I1), the nodes from T.firstT.first are N1,…,NnN_1, \ldots, N_n in order, with Nn.next=nilN_n.next = nil. Write Nn+1N_{n+1} for nil.

Lemma (the scan). In GET, each time line L2 tests its condition, x=Njx = N_j for some jj with 1≤j≤n+11 \le j \le n + 1, and no node among N1,…,Nj−1N_1, \ldots, N_{j-1} has key kk. The loop runs at most nn rounds.

Proof. Line L1 sets x=T.first=N1x = T.first = N_1, and the range of earlier nodes is empty. Assume the claim with x=Njx = N_j and that the test x≠nilx \ne nil succeeds, so j≤nj \le n. If line L3 finds Nj.key=kN_j.key = k, the procedure returns. Otherwise Nj.key≠kN_j.key \ne k, and line L4 sets x=Nj.next=Nj+1x = N_j.next = N_{j+1}, so the claim holds for j+1j + 1. The number n+1−j≥0n + 1 - j \ge 0 drops by exactly 1 per round, so there are at most nn rounds. □\square

GET. If line L3 returns, it returns Nj.valueN_j.value with Nj.key=kN_j.key = k. By (I2) NjN_j is the only node with key kk, and by (I3) its value is M(k)M(k). If the loop ends, x=nilx = nil, so j=n+1j = n + 1, and by the lemma no node has key kk; by (I3), k∉Mk \notin M, and line L5 returns nil. GET writes no field.

PUT. Lines L6 to L9 are the scan of the lemma, with line L8 in place of line L3. If line L8 finds the node of kk, it sets its value to vv and returns. The keys and the list do not change, so (I1) and (I2) hold, and the pairs are those of MM with the pair of kk replaced by (k,v)(k, v), which is (I3) for M[k↦v]M[k \mapsto v]. Otherwise the scan ends with no node of key kk, so k∉Mk \notin M. Line L10 makes a node N0N_0 with key kk, value vv and N0.next=N1N_0.next = N_1 (or nil when n=0n = 0), sets T.first=N0T.first = N_0 and T.n=n+1T.n = n + 1. The list from T.firstT.first is N0,N1,…,NnN_0, N_1, \ldots, N_n, which has n+1n + 1 nodes and ends in nil (I1). The keys are distinct, because kk differs from every key of N1,…,NnN_1, \ldots, N_n (I2). The pairs are those of MM plus (k,v)(k, v), and this is M[k↦v]M[k \mapsto v] since k∉Mk \notin M (I3).

DELETE. Each time line D2 tests its condition, x=Njx = N_j with 1≤j≤n+11 \le j \le n + 1, prev=Nj−1prev = N_{j-1} (nil for j=1j = 1), and no node before NjN_j has key kk; this holds after line D1 and is kept by each round, which moves both pointers one node forward, and the rounds end after at most nn steps as in the lemma. If the loop ends with x=nilx = nil, then k∉Mk \notin M, line D3 returns, and the map without kk is MM. Otherwise x=Njx = N_j is the only node with key kk. If j=1j = 1, line D4 sets T.first=N2T.first = N_2; else it sets Nj−1.next=Nj+1N_{j-1}.next = N_{j+1}. In both cases the list from T.firstT.first is N1,…,Nj−1,Nj+1,…,NnN_1, \ldots, N_{j-1}, N_{j+1}, \ldots, N_n, and line D5 sets T.n=n−1T.n = n - 1, which is its length (I1). Its keys are a subset of distinct keys (I2), and its pairs are those of MM without the pair of kk (I3). ■\blacksquare

Compare counts. In the scan, each round makes one compare of kk with a key. A hit at NiN_i ends in round ii, after ii compares; a miss makes nn rounds and nn compares. This gives the counts of the Complexity section.

Back to Sequential search symbol table