1. void sort(int *arr, int nelt) {
2. int mid,
smallix, bigix, t;
3. if (nelt
<= 1) return;
4.
5. mid = arr[0];
6. smallix =
0;
7. bigix = nelt;
8.
9. while (smallix
< bigix) {
10.
while (smallx < nelt && arr[smallix] <= mid)
11.
++smallix;
12.
while (bigix > 0 && arr[bigix-1] > mid)
13.
bigix--;
14.
if (!(smallix==nelt || 0 == bigix || smallix == bigix)) {
15.
t = arr[smallix];
16.
arr[smallix] = arr[bigix - 1];
17.
arr[bigix - 1] = t;
18.
}
19. }
20. t = arr[0]; arr[0]
= arr[smallix - 1]; arr[smallix - 1] = t;
21. sort(arr, smallix
- 1);
22. sort(arr + smallix,
nelt - smallix);
23. }
Loop Invariants & Mathematical Induction
Basically, there are 2 steps in proving the code correct :-
1) Write the loop invariants and
2) Use induction to show that if the loop invariant is true for ( i
), it is also true for (i + 1).
In the above sort procedure, the loop invariants are :-
Now, apply these predicates to the loop body:
15.
t = arr[smallix];
16.
arr[smallix] = arr[bigix - 1];
17.
arr[bigix - 1] = t;
and we can easily say that the loop maintains a permutation phis relating the current state of the array with its initial state phi0.
What do we know about the outer while loop?
smallix = bigix (We know this from the loop invariant)
20. t = arr[0]; arr[0]
= arr[smallix - 1]; arr[smallix - 1] = t;
It is safe to do the swap. Even though it seems that when smallix =
0, smallix -1 will give us -1, means we are accessing arr[-1](which is
Incorrect!). But, look at the inner while loop of smallix carefully, and
we will notice its going to be executed at least once, so the array range
is within bounds.
21. sort(arr, smallix
- 1);
22. sort(arr + smallix,
nelt - smallix);
Similarly, for the above two recursive calls the array range is going to be within bounds.
Finally, by induction hypothesis we can say that the code is correct and the array is going to be sorted.