|
|
|
|
|
|
|
|
Sorting Algorithms
Sorting is rearranging the elements in a data structure (array or linked list) so that after the procedure is done, they are ranked by their size (in either ascending or descending order)
- Bubble Sort algorithm sorts the elements by bubbling up the largest in the subarray under consideration into the largest not yet taken care of location of the array. This is achieved by comparing every two neighbouring elements starting from the begining to the last location that's still in consideration.
Time Complexity Analysis of Bubble Sort :
n = a.length
(1) T(n) = Touter_for(n) = pass=1Spass=n-1(tpass)
(2) tpass =
C + Tinner_for (pass),
where C is a constant (sum of constants representing
constant time operations involved).
(3) Tinner_for (pass) = i=0Si=n-pass-1(D
+ tif ),
where D is a constant (sum of constants representing
constant time operations involved).
tif = ta[ i
] > a[ i + 1 ] + thold
= a[i] + ta[i] = a[i+1]
+
ta[i+1] = hold= E+F(constant),
if the condition succeeded
tif = ta[
i ] > a[ i + 1 ] = E (constant),
if the condition failed.
(4) tif <= E+F (constant).
Going back to (3), we get :
(5) Tinner_for (pass) = i=0Si=n-pass-1(D
+ tif ) = i=0Si=n-pass-1(G)
= G*(n-pass),
where G is a constant = D + tif.
Going back to (2), we get :
(6) tpass =
C + Tinner_for (pass) = C + G*(n-pass),
Going back to (1), we get :
(8) T(n) = Touter_for(n) = pass=1Spass=n-1(tpass)
= pass=1Spass=n-1[C
+ G*(n-pass)]
(9) T(n) = pass=1Spass=n-1C
+ pass=1Spass=n-1[G*(n-pass)]
(10) T(n) = C*(n-1) + G * pass=1Spass=n-1(n-pass)
(11) T(n) = C*n - C + G * pass=1Spass=n-1(pass)
= C*n - C +G*[(n-1)*n/2]
(12) T(n) = C*n - C + (G/2) * n2 - (G/2) *
n = (G/2) * n2 - (C + (G/2)) * n - C
(13) T(n) = a * n2 + b * n + c = Q(n2),
where a=G/2, b=-C-G/2, c=-C are given constants.
for ( int pass = 1; pass < a.length;
pass++ )
{ // passes
for ( int i =
0; i < a.length - pass; i++ )
{ // one pass
if ( a[ i ] > a[ i + 1 ] ) { // one comparison
hold = a[i];
// one swap
a[ i ] = a[ i + 1 ];
a[ i + 1 ] = hold;
}
}
- Selection Sort algorithm sorts the elements by finding the minimal element in the subarray under consideration and swapping it with the element occupying the lowest location in that subarray. This is done first for the entire array, then for the subarray that includes all but the lowest location, then for the subarray that includes all but the lowest two locations, etc., etc....
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(Sequential) |
|
|
- QuickSort algorithm sorts the elements by partitioning array into the left and right partitions which respectively contain only elements <= pivot (left), or >= pivot (right). Pivot is a chosen element in the array. After the partitioning, both partitions are further subjected to the same algorithm (recursively).
A NOTE on Recursion :
QuickSort is a recursive algorithm (making a reference
to itself). Its implementation is a method containing calls to itself.
Therefore, the conventional wisdom of recursion applies :
(i) BASE CASE(S) RULE :
The algorithm has to have ways of resolving some of its
problems non-recursively (i.e. the method implementing the algorithm has
to have at least one branch in which it doesn't call itself).
(ii) CONVERGENCE RULE :
When applied recursively, the algorithm has to converge
to the BASE CASE(S) (i.e. every recursive call in the method has to bring
the method closer to the calls which will result in non-recursive executions).
The above rules are necessary (but not sufficient) conditions for a proper (without infinite loops) recursion.
Example 1:
public int fact(int n) {
if (n<=0)
// BASE CASES
// NON-RECURSIVE
BRANCH
return 1;
else
// RECURSIVE
CASES
// CONVERGENCE
OBVIOUS:
// n is here
positive
// Recursive
call made with argument (n-1)
// i.e. fact(3)
calls fact(2) in 3*fact(2)
//
fact(2) calls fact(1) in 2*fact(1)
//
fact(1) calls fact(0) in 1*fact(0)
//
fact(0) returns 1 into fact(1) in 1*fact(0) = 1*1
//
fact(1) computes 1*1 and returns 1 into fact(2) in 2*fact(1) = 2*1
//
fact(2) computes 2*1 and returns 2 into fact(3) in 3*fact(2) = 3*2=6
return (n*fact(n-1));
}
Example 2 :
public int Fib (int i) {
if ((i==0) || (i==1))
// BASE CASES
// NON-RECURSIVE
BRANCH
return 1;
else if (i<0) {
// BASE CASES
// NON-RECURSIVE
BRANCH
// Error message
return 0;
} else
// RECURSIVE
CASES
// CONVERGENCE
OBVIOUS:
// i is here
greater than 1
// Recursive
calls made with argument (i-1) and (i-2)
// therefore
converging to base case values of 1 and 0
return (Fib(i-1)
+ Fib(i-2));
}
public List mergeSort (List l) {
if (size(l) == 1)
// BASE
CASES
// NON-RECURSIVE
BRANCH
// ONE-ELEMENT
LIST
return l;
else {
breakIntoHalfs(l,
lh, rh);
// RECURSIVE
CASES
// CONVERGENCE
OBVIOUS:
// Recursive
calls made with arguments lh and rh
// which are
halfs of the original list argumen l
return merge(mergeSort(lh),
mergeSort(rh));
}
}