Bubble sort is one of the easiest sorting technique from the point of view of implementation, but the one of the worst to get into practical use. It has best, worst (, and hence average) case all equal to O(n^2)
.
Lets see how? This pseudocode is copied from Wikipedia (and I made little modifications in it). For this question I am not dealing with the optimized code mentioned there, but believe me, that too runs in O(n^2)
. This code will arrange the elements in ascending order.
procedure bubbleSort( A : list of sortable items )
n = length(A)
repeat
for i = 0 to n-2 inclusive do
/* if this pair is out of order */
if A[i] > A[i + 1] then
/* swap them and remember something changed */
swap( A[i-1], A[i] )
end if
end for
until not swapped
end procedure
In Bubble Sort, firstly, We scan the list elements from starting to the second last element. During the scan, we compare the i
th element with the i+1
th element(i.e. the element next to it). If i
th element is greater than its next element, then we swap them(swapping takes constant time, not linear). So during the first scan, we have ran into n-1
operations(or unit jobs), And we have sorted the list, right?
Actually no. You took the largest element in the list to its correct position but we can't say anything about the rest of the elements. So we do the same thing again, scan it in the same way. Then after second scan, we would have taken the second largest element of the list to its correct position. And we keep on repeating this strategy n-1
times, as that would make sure that we have got n-1
elements at their desired position in the list. Now since we have ran a strategy n-1
times (the strategy that itself takes n-1
time units), then the total time taken should be
(n-1)*(n-1)
= n*n + 1 - 2*n // considering part that effects the most
= n*n
And so, Bubble Sort takes O(n^2)
time.
Let us consider the list you mentioned, 5 4 3 2 1, lets sort it.
5 4 3 2 1
4 5 3 2 1
4 3 5 2 1
4 3 2 5 1
4 3 2 1 5
3 4 2 1 5
3 2 4 1 5
3 2 1 4 5
3 2 1 4 5
2 3 1 4 5
2 1 3 4 5
2 1 3 4 5
2 1 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
And that makes up to 16 steps which is exactly equal to (n-1)^2
(and that's not 5^2 = 25!). The thing that you should note, is that if any algorithm runs in O(n^2)
, that does not literally mean that you go on squaring the input size. No algorithm could have been directly written in its exact form(n^2
or n*log(n)
or ...) because the implementations vary from programmer to programmer, but the sole complexity remains the same(here n*n
).
For example, consider above equation (n-1)*(n-1)
. Now let me add that swapping itself took k units of time, then our equation would have been
(n-1)*(n-1 + (k)) = (n-1)*(n+k-1) = n*n + (k - 2)*n - k + 1
Ofc, considering the part of the equation which effects it the most, we again land on n^2
, no matter how one implements swap()!!!(unless constant time).
For any of your implementation of any algorithm (say of n^2
), you can figure out exact number of steps in a similar way, that would result in form of
f(n) = a*n^2 + b*n + c
Putting correct values of a
, b
, c
, you can get exact number of steps that your own implementation takes for a particular input. But when you tell someone the complexity of your code, then it means you need to tell the part of f(n) that has the most weight-age in that equation.
Good Luck.
P.S. :
Consider ^ to be exponentiation and not XOR.
Consider list and arrays to be same for now.