|
COT 5405 Advanced Algorithms Chris Lacher Notes 4: Searching in Sequential Structures |
for ( k = S.Begin() ; k != S.End() ; k = Next(k) ) {}traverses the entire set S, i.e., iterates through all locations in S
Locator SequentialSearch (traversable set S of elements of type T, T t) { for ( k = S.Begin() ; k != S.End() ; k = Next(k) ) { if (t == *k) // *k = notation for "the element at location k" return k; } return S.End(); }
size_t RLowerBound (T* A, size_t L, size_t H, T t) // pre: A[L,H) is sorted - note H is past the end of the search // post: no change in A // return: index of first occurrence of t in A, or // index where t should be inserted to retain sorted order { size_t M; if (L < H) // search range is not empty { M = (L + H)/2; if (A[M] < t) // t is not in [L..M] return RLowerBound (A, M+1, H, t); else // t is not in [M..H) return RLowerBound (A, L, M, t); } else return H; }
size_t LowerBound (T* A, size_t L, size_t H, T t) // pre: A[L,H) is sorted - note H is past the end of the search // post: no change in A // return: index of first occurrence of t in A, or // index where t should be inserted to retain sorted order { size_t M; while (L < H) { M = (L + H)/2; if (A[M] < t) // t is not in [L..M] L = M + 1; else // t is not in [M..H) H = M; } return H; }
unsigned int LowerBound (T* v, unsigned int max, T t) { unsigned int low = 0; unsigned int mid; unsigned int hih = max; while (low < hih) { // (1) low < hih // (2) v[low - 1] < t (if index is valid) // (3) t <= v[hih] (if index is valid) mid = (low + hih) / 2; if (v[mid] < t) low = mid + 1; else hih = mid; // (4) low <= hih // (5) hih - low has decreased // (6) v[low - 1] < t (if index is valid) // (7) t <= v[hih] (if index is valid) } return low; }
Next, prove the invariants one at a time.
Assertion (1) low < hih
Proof:
This asserts that the loop entry condition is true as we enter the loop. True, by definition of loop entry condition. QED
Assertion (2) v[low - 1] < t (if index is valid)
Assertion (3) t <= v[hih] (if index is valid)
Proof:
If the current loop iteration is not the first iteration of the loop, then (2) and (3) just repeat for the record what was true as we exited the previous iteration (assertion (6) and (7)). We only need to verify (2) and (3) in the case of the first iteration.
In the first iteration, we know that low = 0 and hih = max. Thus, low - 1 = -1 and hih = max are each invalid index values. The assertions (2) and (3) are therefore true by default. QED
The remaining assertions are placed at the end of the loop body, so they must be proved under the assmption that (1), (2), and (3) were true when entering the loop body and then the body has been executed. There are two cases:
Case 1: v[mid] < t
Assertion (4) low <= hihProof:
low = mid + 1 = (low + hih)/2 + 1 < (hih + hih)/2 + 1 // by (1) = hih + 1Because we are working with integers, (low < hih + 1) implies that (low <= hih).Assertion (5) hih - low has decreased
Proof:
hih - low = hih - (mid + 1) = hih - mid - 1 < hih - mid = hih - (old_low + hih)/2 = hih - hih/2 - old_low/2 = old_hih - old_hih/2 - old_low/2 // because hih = old_hih <= old_hih - old_low/2 - old_low/2 // because old_low <= old_hih = old_hih - old_lowTherefore, hih - low has decreased.Assertion (6) v[low - 1] < t (if index is valid)
Proof:
v[low - 1] = v[mid + 1 - 1] = v[mid] < tAssertion (7) t <= v[hih] (if index is valid)
Proof:
hih has not changed values, so this is true in the current iteration because it was true in the previous iteration.
Case 2: v[mid] >= t
Assertion (4) low <= hih
Proof:
hih = mid = (low + hih)/2 >= (low + low)/2 // by (1) = lowAssertion (5) hih - low has decreased
Proof:
hih - low = mid - low = (old_hih + old_low)/2 - low = (old_hih + old_low)/2 - old_low // because low = old_low = (old_hih + old_low)/2 - (old_low + old_low)/2 = (old_hih - old_low)/2 < old_hih - old_low // because old_hih - old_low > 0Therefore, hih - low has decreased.
Assertion (6) v[low - 1] < t (if index is valid)
Proof:
low has not changed values, so this is true in the current iteration because it was true in the previous iteration.
Assertion (7) t <= v[hih] (if index is valid)
Proof:
v[hih] = v[mid] >= t
We have now proved all of the loop invariants (1) through (7). It remains to prove that the algorithm terminates and that it delivers what it promises. The loop invariants are key to the proofs.
Assertion: The LowerBound algorithm terminates.
Proof: Loop invariant (5) says that the quantity hih - low decreases in each loop iteration. Invariant (4) says that this quantity is non-negative. Therefore, the loop terminates when hih - low collides with zero.
Assertion: The return value of LowerBound is the lower bound index for t in v, that is, the smallest index i such that t <= v[i].
Proof: When the algorithm terminates, low = hih. Assertion (6) says that no index smaller than low has element equal to t. Assertion (7) says that the element with index hih (= low) is no smaller than t. This makes low = hih the lower bound index.
Assertion: If t is in v, then LowerBound is the index of the first occurance of t in v.
Proof: (Left as an exercise.)