A case is a class of inputs for which you consider your algorithm's performance. The best case is the class of inputs for which your algorithm's runtime has the most desirable asymptotic bounds. Typically this might mean there is no other class which gives a lower Omega bound. The worst case is the class of inputs for which your algorithm's runtime has the least desirable asymptotic bounds. Typically this might mean there is no other class which gives a higher O bound. The average case has nothing to do with desirability of bounds but looks at the expected value of the runtime given some stated distribution of inputs. Etc. You can define whatever cases you want.
Imagine the following algorithm:
Weird(a[1...n])
if n is even then
flip a coin
if heads then bogosort(a[1...n])
else if tails then bubble_sort(a[1...n])
else if n is odd then
flip a coin
if heads then merge_sort(a[1...n])
else if tails then counting_sort(a[1...n])
Given a list of n
integers each between 1 and 10, inclusive, this algorithm sorts the list.
In the best case, n
is odd. A lower bound on the best case is Omega(n)
and an upper bound on the best case is O(n log n)
.
In the worst case, n
is even. A lower bound on the worst case is O(n^2)
and there is no upper bound on the worst case (since bogosort may never finish, despite that being terribly unlikely).
To define an average case, we would need to define probabilities. Assuming even/odd are equally likely for all n
, then there is no upper bound on the average case and a lower bound on the average case is Omega(n^2)
, same as for the worst case. To get a different bound for the average case, we'd need to define the distribution so that n
being even gets increasingly unlikely for larger lists. Maybe the only even-length list you typically pass into this algorithm has length 2, for example.