Showing posts with label Sorting. Show all posts
Showing posts with label Sorting. Show all posts

Monday, October 22, 2012

Inversion

Let A[1..n] be an array of n distinct numbers.If i < j and A[i] > A[j], then the pair (i,j) is called an inversion of A.
Consider the array (2,3,8,6,1). Inversions in array are (8,6), (2,1), (3,1) , (8,1), (6,1).

Write program to count the number of inversion in array.

/*
 * CountInverion0 : This is modified version of insertion sort. Time Complexity : O(n^2)
 */
int CountInversion0(int a[], int n)
{
    int i,j,count=0;
    for(i=1; i<n; i++) {
             for(j=0; j<i; j++)
                      if(a[j] > a[i])
                              count++;
    }
    return count;
}

/*
 * CountInversion1 : Modifed version of Merge sort. Uses Divide and Conquer Methodlogy.
 * TimeComplexity: O(n*log(n)).
 */
int CountInversion1(int A[], int start, int end)
{
    int i,x,y;
    int z=0;
    if((end-start) == 0) return 0;
    else if(start < end) {
        i = (start+end)/2;
        x = CountInversion1(A, start , i);
        y = CountInversion1(A, i+1, end);
        z = CountSplitInversion(A,start,end,i);
        return x+y+z;
    }
}
/*
 * Helper function: sorts array and also count the number of inversion.
 * Hint : in case of merge sort, while merging if we copy the number from 2nd array to array,
 * number of elements lefts in first array adds to the number of inversions.
 */
int CountSplitInversion(int a[],int start, int end, int div)
{
    int i,j,k,lc = (div-start)+1,rc = (end-div),*l,*r,count = 0;
    l = (int *) malloc(sizeof(int) * (lc+1));
    r = (int *) malloc(sizeof(int) * (rc+1));
    for(i=0; i < lc; i++)
        l[i] = a[start + i];
    for(i=0; i < rc; i++)
        r[i] = a[div+i+1];
    for(k=start,i=0,j=0; k <= end && (i < lc) && (j <rc) ;k++)
    {
        if(l[i] <= r[j]) {
            a[k] = l[i]; i++;
        }
        else {
            a[k] = r[j]; j++;
            count +=  (lc - i);
        }
    }
    if(i < lc) {
        for(;k<=end && i<lc ;k++)
            a[k] = l[i];
    }
    if(j < rc) {
        for(;k<=end && j<rc ;k++)
            a[k] = r[j];
    }
    return count;
}

Wednesday, October 10, 2012

Sort a List using Merge Sort

Write Merge sort routine for sorting linked list

/*
 * Merge Sort
 */
void MergeSort(nodeptr* headRef) {
    nodeptr head = *headRef;
    nodeptr a;
    nodeptr b;

    if ((head == NULL) || (head->next == NULL)) {
        return;
    }

    FrontBackSplit(head, &a, &b); // Split list into 'a' and 'b' sublists

    MergeSort(&a); // Recursively sort the sublists  'a' and 'b'
    MergeSort(&b);

    *headRef = SortedMerge(a, b); //merge the two sorted lists together
}

/*
 * Takes two lists sorted in increasing order, and splices their 
 * nodes together to make one big sorted list which is returned.
 */
nodeptr SortedMerge(nodeptr a, nodeptr b)
{
    nodeptr result = NULL;
    nodeptr* lastPtrRef = &result;

    while (1) {
        if (a == NULL) {
            *lastPtrRef = b;
            break;
        }
        else if (b == NULL) {
            *lastPtrRef = a;
            break;
        }
        if (a->data <= b->data) {
            MoveNode(lastPtrRef, &a);
        } else {
            MoveNode(lastPtrRef, &b);
        }
        lastPtrRef = &((*lastPtrRef)->next);
    }
   
    return(result);
}

/*
 * Split the nodes of the given list into front and back halves,
 * and return the two lists using the reference parameters.
 * If the length is odd, the extra node should go in the front list.
 */
void FrontBackSplit(nodeptr source, nodeptr* frontRef, nodeptr* backRef)
{
    nodeptr singlestep = NULL;
    nodeptr doublestep = NULL;
    if(source == NULL) {
        *frontRef = NULL;
        *backRef = NULL;
    } else {
        *frontRef = source;
        doublestep = source->next;
        singlestep = source;
        while(doublestep != NULL) {
            if(doublestep->next != NULL)
                doublestep = doublestep->next->next;
            else 
                break;
            singlestep = singlestep->next;
        }
        *backRef = singlestep->next;
        singlestep->next = NULL;
    }
}


Monday, October 8, 2012

Sorting List using Insertion Sort

Write a program to sort a list using insertion sort.

/*
 * Node of list
 */
struct node {
       int data;
       struct node* next;
};
typedef struct node* nodeptr;

/*
 * Insert a node into its sorted position
 */
void SortedInsert(nodeptr* head, nodeptr newNode)
{
    nodeptr currentNode = *head;
    nodeptr prevNode = NULL;
    while(currentNode != NULL && currentNode->data < newNode->data) {
        prevNode = currentNode;
        currentNode = currentNode->next;
    }
    newNode->next = currentNode;
    if(prevNode == NULL)
        *head = newNode;
    else
         prevNode->next = newNode;
} 

/* 
 * Insert Sort List
 */
void InsertSort(nodeptr* head)
{
    nodeptr current = *head;
    nodeptr list = NULL;
    nodeptr next = NULL;
    while(current!= NULL)
    {
        next = current->next;
        SortedInsert(&list,current);
        current = next;
    }
    *head = list;
}

Thursday, May 10, 2012

Merge Sort

The merge sort algorithm closely follows the divide-and-conquer paradigm. Intuitively, it operates as follows.
Divide: Divide the n-element sequence to be sorted into two subsequences of n/2 elements each.
Conquer: Sort the two subsequences recursively using merge sort.
Combine: Merge the two sorted subsequences to produce the sorted answer.

We use this technique to sort a file in the following way. Divide the file into n subfiles of size 1 and merge adjacent (disjoint) pairs of files. we then have approximately n/2 files of size 2. Repeat this process until there is only one file remaining of size n.

Below is the nonrecursive procedure expaining merge sort.

#define NUMELTS  .... // .... is to be put as the number of elements in array.

void MergeSort(int x[], int n)
{
    int aux[NUMLETS], i, j, k, l1, l2, size, u1, u2;
   
    size = 1; / * Merge files of size 1;
    while(size < n) {
        l1 = 0; /* initialize lower bounds of first file */
        k = 0; /* k is index for auxiliary array */
        while(l1+size < n) { /* Check to see if there are two files to merge */
            /* Compute remaining indices */
            l2 = l1+size;
            u1 = l2-1;
            u2 = (l2+size-1 < n) > l2+size-1 : n-1;
            /* proceed through the two subfiles */
            for(i=l1,j=l2;i<=u1 && j<=u2; k++)
                /* Enter smaller into the aux array */
                if(x[i] <= x[j])
                    aux[k]=x[i++];
                else
                    aux[k] = x[j++];
            /* At this point, one of the subfiles has been exhausted.
             * Insert any remaining portions of the other file
             */
            for(;i<=u1;k++)
                aux[k] = x[i++];
            for(;j<=u2;k++)
                aux[k] = x[j++];
            /* advance l1 to start of the next pair of files. */
            l1 = u2 +1;
        }
        /* Copy any remaining single file */
        for(i=l1;k<n;i++)
            aux[k++]=x[i];
        /* Copy aux into x and adjust size */
        for(i=0;i<n;i++)
            x[i]=aux[i];
        size *= 2;
    }
}

Average case time complexity of merge sort is O(nlogn) but it requires O(n) additional space for the auxiliary array.

Quick Sort

Quick sort applies the divide and conquer paradigm. Let x be an array and n the number of elements to be sorted. Choose an element a from a specific position within the array. Suppose that the elements of x are partitioned so that a is placed into position j and the following conditions hold:
  • Each of the elements in positions 0 through j-1 is less than or eual to a.
  • Each of the elements in position j+1 through n-1 is greater than or equal to a.
If this conditions holds for a particular a and j, a is the jth smallest element of x, so that a remains in position j when the array is completely sorted.If foregoing process is repeated with the subarays x[0] through x[j-1] and x[j+1] through x[n-1] and any subarrays created by the process in successive iterations, the final result is a sorted file.

Below is procedure for quicksort.

void QuickSort(int x[],int lb,int ub)
{
    int j;
    if(lb>=ub)
        return; /* array is sorted */
   
    partition(x,lb,ub,&j);
    /* partition the elements of the subarray such that one of the elements is now at position x[j] and
     * x[i] <= x[j] for lb <=i < j
     * x[i] >= x[j] for j < i <=ub
     */
   
    QuickSort(x,lb,j-1);     /* sort the subarray between positions lb and j-1 */
    QuickSort(x,j+1,ub);    /* sort the subarray between positions j+1 and ub */
}

Now we need to implement the procedure partition.The object of partition is to allow a specific element to find its proper position with respect to the others in the subarray.
For this we need to consider a pivot element which will be at its proper position after partition. For time being consider pivot element a=x[lb]. Two pointers, up and down are initialized to the upper and lower bounds of the subarray, respectively. At any point during execution, each element in a position above up is greater than or equal to a, and each element in a position below down is less than or equal to a. The two pointers are moved towards each other in following fashion.
  • Repeatedly increase the pointer down by one position until x[down] > a.
  • Repeatedly decrease the pointer up by one position until x[up] <= a.
  • if up > down, interchange x[down] with x[up]
The process is repeated until the condition in last step fails(up<=down), at which point x[up] is interchanged with x[lb](which equals pivot element a), whose final position was sought, and j is set to up.

Below is procedure partition.

void partition(int x[],int lb, int ub, int *pj)
{
    int a, down, temp, up;

    a=x[lb];
    up=ub;
    down=lb;

    while(down < up) {
        while(x[down] <= a && down < up)
            down++;
        while(x[up] > a)
            up--;
        if(down < up) {
            temp = x[down];
            x[down] = x[up];
            x[up] = temp;
        }
    }
    x[lb] = x[up];
    x[up] = a;
    *pj = up;
}
   
Average Time Complexity of quick sort is O(nlogn). Its worst case is when the array is sorted and time complexity in that case is O(n2). It requires O(logn) additional space for the stack.

It is possible to speed up quick sort for sorted files by choosing a random elements of each subfile as the pivot element.If file is nearly sorted this might be a good strategy(may choose a middle element as pivot element). However if nothing is known above the file, such a strategy doesnot improve the worst case behaviour.

Lets see quick sort example.If an array is given as
    25 57 48 37 12 92 86 33
pivot element a = 25. so after 1st iteratin, 25 will be at its proper postion, and the resulting array will be.
    12 25 57 48 37 92 86 33
it will divide the array into two subparts (12) and ( 57 48 37 92 86 33) which needs to be sorted.
proceeding in this way following will be output after successive iterations.
    12 25 (48 37 33 57 92 86)
    12 25 (48 37 33) 57(92 86)
    12 25 (37 33) 48 57 (92 86)
    12 25 (33) 37 48 57 (92 86)
    12 25 33 37 48 57 (92 86)
    12 25 33 37 48 57 (86) 92
    12 25 33 37 48 57 86 92

Wednesday, May 9, 2012

Insertion Sort

An insertion sort is one that sorts a set of records by inserting records into an existing sorted file.

Below is the insertion sort procedure code

void InsertionSort(int x[],int n)
{
    int i,k,y;
    for(k=1;k<n;k++)
    {
        y=x[k];
        for(i=k-1;i>=0 && y<x[i];i--)
            x[i+1] = x[i];
        x[i+1]=y;
    }
}

Time complexity iss O(n2) if the file is initially sorted in reverse order. On average case also its time complexity is O(n2).

Selection Sort

A selection sort is one in which successive elements are selected in order and placed into their proper sorted positions. The elements of the input may have to be preprocessed to make the ordered selection possible.
Selection sort consists entirely of a selection phase in which the largest of the remaining elements,large, is repeatedly placed at its proper position i, at the end of the array.

Below is the working procedure code.

void SelectionSort(int x[], int n)
{
    int i,indx,j,large;
   
    for(i=n-1;i>0;i--)
    {
        large = x[0];
        indx = 0;
        for(j=1;j<=i;j++)
            if(x[j]>large)
            {
                large = x[j];
                indx = j;
            }
        x[indx] = x[i];
        x[i] = large;
    }

The above procedure will sort the array in ascending order.
Consider the elements of array are
25 57 48 37 12
Here we will see the state of array after each iteration.
iteration 0     25 57 48 37 12
iteration 1    25 12 48 37 57
iteration 2    25 12 37 48 57
iteration 3    25 12 37 48 57
iteration 4    12 25 37 48 57

Average time complexity of selection sort is O(n2).

Bubble Sort

The basic idea of bubble sort is to pass through the file sequentially several times. Each pass consists of comparing each element in the file with its successor(x[i] with x[i+1]) and interchanging the two elements if they are not in proper order.

Below is the working procedure code.

void BubbleSort(int x[], int n)
{
    int tmp,i,j;
    int switched = 1;
   
    for(i=0;i<n-1 && switched==1;i++)
    {   
        /* idea of using switched variable is if there
         * is no interchanging of element in one complete
         * array iteration means array is sorted .
         */
        switched = 0;
        for(j=0;j<n-i-1;j++)
            if(x[j]>x[j+1])
            {
                switched = 1;
                tmp = x[j];
                x[j] = x[j+1];
                x[j+1] = tmp;
            }
    }
}

The above procedure will sort the array in ascending order.
Consider the elements of array are
25 57 48 37 12
Here we will see the state of array after each iteration.
iteration 0     25 57 48 37 12
iteration 1    25 37 48 12 57
iteration 2    25 37 12 48 57
iteration 3    25 12 37 48 57
iteration 4    12 25 37 48 57

Time complexity of bubble sort in average case is O(n2). But in case if the file is already sorted time complexity of this sort will be O(n).

Sorting

It is rearranging a collection of items into increasing or decreasing order. Sorting is used to preprocess the collection to make searching faster, as well as to identify items that are similar.

A sort can be classified as
internal - if the records that it is sorting are within main memory.
external - if some of the records that it is sorting are in auxiliary storage.

There are large number of sorting techniques. Some of them  with there average time complexity are:
Bubble Sort       O(n2)
Selection Sort    O(n2)
Insertion Sort     O(n2)
Quick Sort         O(nlogn)
Merge Sort        O(nlogn)
Heap Sort          O(nlogn)

An ideal sort is an inplace sort whose additional space requirement is O(1).

A sorting technique is said to be stable if for all records i and j such that k[i] equals k[j], if r[i] precedes r[j] in original file, r[i] precedes r[j] in the sorted file. Here, k[i] refer to key associated with each record r[i].

which sort is better we can't tell it totally depends upon the problem characteristics where which will be more suitable.