The College of New Jersey
Computer Science Department
CMSC 410: Advanced Algorithms
Fall 2001


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....





Homework #5 (06/19) :
Derive the time complexity formula for the Selection Sort (showing that it's a quadratic algorithm). Hint : Use the derivation of the Bubble Sort's time complexity formula as your guidance.



 
Algorithm
Average Case Time Complexity
Worst Case Time Complexity
Bubble Sort
O(n2)
O(n2)
Selection Sort
 O(n2)
 O(n2)
Quick Sort
O(n*log2n)
O(n2)
MergeSort
(Sequential)
O(n*log2n)
O(n*log2n)

- 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));

}





Homework #6 (06/26) :
Using the array discussed in class (20, 67, 45, 66, 5, 15, 33, 6, 2, 6)
(i)    Apply the quicksort algorithm by hand and show all the partitions formed along the way.
(ii)    Draw a tree of calls (as shown in class) indicating :
        (a) calls made by quicksort to quicksort listing the partition boundaries in each call,
        (b) the order in which the calls were made.


- MergeSort algorithm sorts the elements by first dividing list into halfs until one element (sorted) halfs are obtained. Thenafter, the algorithm merges sorted halfs into a sorted union of them. The pseudocode of the algorithm is listed below.

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));
    }

}