Correctness of bubblesort

Bubblesort is a popular, but inefficient, sorting algorithm. It works by repeatedly swapping adjacent elements that are out of order.

$$\textsc {Bubblesort }(A)$$$$\begin{aligned}1& \quad \textbf {for }i=1\textbf { to }A.length-1 \\2& \quad \qquad \textbf {for }j=A.length\textbf { downto }i+1 \\3& \quad \qquad \qquad \textbf {if }A[j]<A[j-1] \\4& \quad \qquad \qquad \qquad \text {swap }A[j]\text { and }A[j-1] \\\end{aligned}$$
  1. Let \(A'\) denote the output of \(\textsc {Bubblesort(A)}\) . To prove that \(\textsc {Bubblesort}\) is correct, we need to prove that it terminates and that
\[A'[1] \leq A'[2] \leq \cdots \leq A'[n] \tag{2.3}\]

where \(n = A.length\). In order to show that \(\textsc {Bubblesort}\) actually sorts, what else do we need to prove?

The next two parts will prove inequality (2.3).

  1. State precisely a loop invariant for the for loop in lines 2–4, and prove that this loop invariant holds. Your proof should use the structure of the loop invariant proof presented in this chapter.
  2. Using the termination condition of the loop invariant proved in part (b), state a loop invariant for the for loop in lines 1–4 that will allow you to prove inequality (2.3). Your proof should use the structure of the loop invariant proof presented in this chapter.
  3. What is the worst-case running time of bubblesort? How does it compare to the running time of insertion sort?

A. Required Proof of Correctness

We also need to prove that \(A'\) consists of the elements of \(A\) but in sorted order.

B. Loop Invariant for Inner Loop

The loop invariant for the for loop in lines 2–4 can be stated as follows:

At the start of each iteration of the for loop, the subarray \(A[j \ldots n]\) consists of the elements originally in \(A[j \ldots n]\) before entering the loop but possibly in a different order and the first element is the smallest among them.

And here is how the three necessary properties hold for the loop invariant:

Initialization: Initially the subarray contains only the last element \(A[n]\) and this is the smallest element of the subarray.

Maintenance: In every step we compare \(A[j]\) with \(A[j - 1]\) and make \(A[j - 1]\) the smallest among them. So, after the iteration, the length of the subarray increases by one and the first element is the smallest of the subarray.

Termination: The loop terminates when \(j = i + 1\). At that point also the length of the subarray increases by one and the first element is the smallest of the subarray as we swap \(A[i + 1]\) with \(A[i]\).

C. Loop Invariant for the Outer Loop

The loop invariant for the for loop in lines 1–4 can be stated as follows:

At the start of each iteration of the for loop, the subarray \(A[1 \ldots i - 1]\) consists of the elements that are smaller than the elements in the subarray \(A[i \ldots n]\) in sorted order.

And here is how the three necessary properties hold for the loop invariant:

Initialization: Initially the subarray \(A[1 \ldots i - 1]\) is empty and trivially this is the smallest element of the subarray.

Maintenance: From part (b), after the execution of the inner loop, \(A[i]\) will be the smallest element of the subarray \(A[i \ldots n]\). And in the beginning of the outer loop, \(A[1 \ldots i - 1]\) consists of elements that are smaller than the elements of \(A[i \ldots n]\), in sorted order. So, after the execution of the outer loop, subarray \(A[1 \ldots i]\) will consists of elements that are smaller than the elements of \(A[i + 1 \ldots n]\), in sorted order.

Termination: The loop terminates when \(i = A.length\). At that point the array \(A[1 \ldots n]\) will consists of all elements in sorted order.

D. Running Time of Bubblesort

In the worst-case (reverse sorted array), bubblesort will iterate over the whole array for each element, i.e. for each element bubble sort will perform \(n\) comparisons and swaps. Therefore, worst-case running time of bubblesort is \(\Theta(n^2)\).

Although insertion also runs at \(\Theta(n^2)\) worst-case time, the number of assignments (swaps) performed in bubblesort is way more than that of insertion sort. So, the constant factors in the running time will be much larger for bubblesort compared to that of insertion sort. This means, for the same input size, insertion sort will run faster than bubblesort.