Saturday 21 March 2015

Quick Sort in Java


Quick sort works on the principle of divide and conquer.
Divide the list in 2 sub-lists, find a pivot element such that its actual position divides the list further in 2 lists.
So the pivot element resides at its actual position and then recursively find location of other elements. At the end of processing each element will get its actual(sorted) position and array will be sorted.

Algorithm QuickSort
1. QuickSort(Arr, p, r) 
2. if(p < r) 
3. q=findPivot(Arr,p,r); //find pivot and its location [ takes O(n) ] 
4. QuickSort(Arr, p,q-1); //left sub array 
5. QuickSort(Arr, q+1,r); // right sub array Algorithm for partition to find pivot 

Algorithm for partition to find pivot :
 PARTITION (Arr, p, r )
 1. x =A[r]
 2. i = p-1
 3. for j =p to r-1
 4.    if A[j] <= x
 5.     i=i+1
 6.    exchange A[i]  with A[j]
 7. exchange A[i+1] with x
 8. return i+1


Following program implements Quick sort in java.

/**
 * @author vikky.agrawal
 *
 */
public class QuickSort {

 
 int[] arr;
 
 QuickSort(){
  arr=new int[] { 5, 3, 1, 2, 9, 8 };
 }
 
 /**
  * @param args
  */
 public static void main(String[] args) {
  
  QuickSort obj = new QuickSort();
  obj.operate();
 }
 
 
 public void operate(){
  
  System.out.println("Array before sortings: ");
  printArray();
  quickSort(arr,0,5);

  System.out.println("Sorted array : ");
  printArray();
 }
 
 
 public void quickSort(int[] arr, int p, int r){
  
  if(p<r){
   int q= findPivot(arr,p,r);
   quickSort(arr, p, q-1);
   quickSort(arr, q+1, r);
  }
  
 }
 
 
 /**
  * Algorithm for partition to find pivot
  * 
  * PARTITION.A;p;r
  * 1 x =A[r]
  * 2 i = p-1
  * 3 for j =p to r-1
  * 4   if A[j] <= x 
  * 5   i=i+1 
  * 6   exchange A[i]  with A[j]
  * 7 exchange A[i+1] with x 
  * 8 return i+1
  */
 
 public int findPivot(int[] arr, int p, int r){
  
  int x=arr[r];
  int i=p-1; 
  
  for(int j=p ;j<r; j++){
   if(arr[j]<= x){
    i++;
    int temp=arr[i];
    arr[i]=arr[j];
    arr[j]=temp;
   }
  }  
  
  arr[r]=arr[i+1];
  arr[i+1]=x;
  return i+1;
 }
 
 public void printArray(){
  for (int a : arr) {
   System.out.print(a + " ");
  }
  System.out.println();
 }
}
Complexity analysis:
In average case scenario each problem is divided in 2 sub problems, hence total time required will be:
T(n)= 2T(n/2)+O(n) where O(n) is to find pivot and its location.
Using Master theorem solution to above equation comes as O(n logn)(Avg case)
In worst case scenario array may be divided in (1, n-2) in that case total time required will be
 T(n)= T(1)+T(n-2)+O(n) and solution to this equation becomes : O(n^2) (Worst case)

 But worst case is rare in quick sort and analysis shows that mostly average case occurs with complexity O(n logn).
For more analysis check wiki: Quicksort#analysis  

Facts:
1. Worst case for quick sort occurs when array is already sorted.
2. Worst case also occurs when all the elements are same.

3. Quick sort gives better results than Mergesort in average case.



Merge Sort in Java

Merge sort works on the principle of divide and conquer.
Divide the list in 2 sub-lists, and repeat until there is only 1 element, a sub-list with single element is already sorted.
Now merge the sorted sub-lists to get a sorted list until there is only a single sorted list.

Algorithm:
1. MergeSort(Arr, p ,r)
2. if(p < r)
3.  q=[p+r/2];
4.  MergeSort(Arr, p,q);    //left sub array
5.  MergeSort(Arr, q+1,r);  // right sub array
6.  Merge(Arr, p , q, r);   //Merge, sorted sub arrays [takes O(n) ]

Following program implements Merge sort in java.


/**
 * @author Vikky.Agrawal
 *
 */
public class MergeSort {

 
 int[] arr;
 
 MergeSort(){
  arr=new int[] { 5, 3, 1, 2, 9, 8 };
 }
 
 /**
  * @param args
  */
 public static void main(String[] args) {

  MergeSort obj = new MergeSort();
  obj.operate();
 }
 
 
 public void operate(){
  System.out.println("Array before sortings: ");
  printArray();
  mergeSort(arr,0,5);

  System.out.println("Sorted array : ");
  printArray();
 }
 
 
 public void mergeSort(int[] arr, int p, int r){
  if(p<r){
   int q=(p+r)/2;
   mergeSort(arr, p, q);
   mergeSort(arr, q+1, r);
   merge(arr,p,q,r);
  }
 }
 
 public void merge(int[] arr, int p, int q, int r){
  
  int length=arr.length;
  int[] tempArray =new int[length];

  for (int i=0;i<length; i++) {
   tempArray[i]=arr[i];
  }
  
  int temp=p;
  int i=p,j=q+1;
  for(; i<=q && j<=r ; ){
   if(tempArray[i] < tempArray[j]){
    arr[temp++]=tempArray[i];
    i++;
   }else{
    arr[temp++]=tempArray[j];
    j++;
   }
  }
  
  while(i <= q){
   arr[temp++]=tempArray[i];
   i++;
  }
  
  while(j < r){
   arr[temp++]=tempArray[j];
   j++;
  }
 }
 

 public void printArray(){
  for (int a : arr) {
   System.out.print(a + " ");
  }
  System.out.println();
 }

}


Complexity analysis:
Since each problem is divided in 2 sub problems and then these sub problems merged.
Total time required will be T(n)= 2T(n/2)+O(n)
where O(n) is to merge sub problems.
Using Master theorem #case2 solution to above equation comes as O(n logn).

In worst case scenario Merge sort beats Quick sort which requires O(n^2)
worst case time.

For more analysis follow wikipedia: Merge_sort#Analysis
In the worst case, the number of comparisons merge sort makes is equal to or slightly smaller than (n logn - 2 logn + 1), which is between (n lg n - n + 1) and (n lg n + n + O(lg n))

Master theorem for complexity analysis

Master theorem is used to analyze complexity of many problems in divide and conquer category.
Master theorem deals with recurrence relations in the form:

T(n)= aT(n/b)+f(n)
where:
n is size of original problem
a is number of sub-problems
n/b size of sub-problems(assuming sub-problems of equal size)

f(n) is the time required to conquer(dividing or merging) the sub-problems;

such as merging in merge sort or finding pivot in quick sort</em>

There are 3 cases to solve such kind of recurrences:
In each of three cases we compare f(n) with (n logba). Polynomially larger of these functions determines solution.

Case 1:
If f(n) = O( nc ) where c < logba
then solution becomes T(n) = θ(n logba)

In first case, comparison states that (n logba) is larger than f(n),hence solution θ(n logba)

For example:
T(n) = 9T(n/3)+1000n2
a=9, b=3, f(n)=n2 (leaving constant terms)
n logba = n log39 = n3 which is polynomially greater than n2.
Hence solution T(n) = θ(n3)

Case 2:
 if f(n) = θ(n log b a )
then solution becomes T(n) = θ(n logba logn)
In second case, comparison states that (n logba) is equal to f(n), we multiply f(n) by logarithmic factor hence solution θ(n logba logn)

For example:
T(n) = T(n/2)+c (Binary search)
a=1, b=2, f(n)=c (constant)
n logba = n log21 = n0 = 1 which is equal to f(n).
Hence solution T(n) = θ(logn)

Case 3:
if f(n) = Ω( nc ) where c > logba
and it is also true that af(n/b) <= kf(n) for some constant k < 1,
and sufficiently large n.
then solution becomes T(n) = θ( f(n) )

In third case comparison states that (n logba) is smaller than f(n).
hence solution θ( f(n) )

For example:
T(n) = 2T(n/2)+10n2 a=2, b=2, f(n)=n2 (leaving constant terms)
n logba = n log22 = n which is polynomially smaller than n2.
Hence solution T(n) = θ(n2)  

Facts :
Master theorem doesn't apply if function is not polynomially large enough to determine solution.
 eg : T(n) = 2T(n/2)+nlogn here a=2,b=2
f(n) = n logn;
nlogba = n;
so f(n) is greater than nlogba but not polynomially large enough, its large by a factor of logarithm hence can't determine solution.

Sunday 15 March 2015

Insertion Sort in java


Insertion sort takes the input array and sorts it, all the elements in the array before the loop invariant (loop variable) are sorted. Hence we start our loop from index 1 and iterate.(Assuming that first element is sorted) While looping current item is compared with sorted array and its actual index identified, after loop completion it is inserted at its actual location.
Following program implements Insertion sort in java.
/**
 * @author vikky.agrawal
 * 
 */
public class InsertionSort {

	
	int[] arr;
	
	InsertionSort(){
		arr=new int[] { 5, 3, 1, 2, 9, 8 };
	}
	
	/**
	 * @param args
	 */
	
	public static void main(String[] args) {

		InsertionSort obj = new InsertionSort();
		obj.operate();
	}
	
	public void operate(){

		System.out.println("Array before sortings: ");
		printArray();
		sort();

		System.out.println("Sorted array : ");
		printArray();
	}
	

	/**
	 * Insertion Sort algo: 
	 * 1 for j=1 to Arr.length 
	 * 2 key= Arr[j]; 
	 * 3 //Insert Arr[j] into the sorted sequence Arr[0...j-1].
	 * 4 i=j-1; //initialization for looping 
	 * 5 while (i>=0 and Arr[i] >key) 
	 * 6   Arr[i+1]=Arr[i] 
	 * 7   i=i-1; 
	 * 8 Arr[i+1] = key
	 */

	public int[] sort() {

		int length = arr.length;
		int i = 0;
		int key = 0;
		for (int j = 1; j < length; j++) {
			i = j - 1;
			key = arr[j];
			while (i >= 0 && arr[i] > key) {
				arr[i + 1] = arr[i];
				i--;
			}
			arr[i + 1] = key;
		}

		return arr;
	}

	public void printArray(){
		for (int a : arr) {
			System.out.print(a + " ");
		}
		System.out.println();
	}
}
Complexity analysis of Insertion sort :
Outer loop runs for n-1 times.In the worst case the inner while loop will execute for each element and hence will sum up as:
(∑ tj-1 where j=2 to n) = 1+2+3+4+-------+n-1 = n*(n-1)/2 = n^2.
Hence to sum up the overall complexity worst case time required in insertion sort will be equal to O(n^2).

When to use insertion sort / Characteristics of Insertion sort
1. Insertion sort should be used when data is nearly sorted, in such cases inner while loop won't get executed and performance of insertion sort remains better than its worst case.
2. Insertion sort could be used when data size is smaller, as it requires little/no overhead.
3. It's stable sort (i.e. does not change the relative order of elements with equal values after sorting)
4. In-place sorting- requires constant amount of extra space.

Rotate a linked list anti clock wise for given number of nodes


Java program to rotate a given Linked list anti clockwise for given no of nodes.
/**
 * @author vikky.agrawal
  */

public class LinkedList {

	Node node = null;	

	public static void main(String[] args) {

		LinkedList list = new LinkedList();
		list.operations();

	}

	public void operations() {

		this.node = new Node(10);

		for (int i = 1; i < 6; i++) {
			add(node, (int) (Math.random() * 100));
		}
		this.rotateACW(node, 8);
	}
	
	/**
	 * Rotate a linked list Anti clock wise for given number of nodes
	 */

	public void rotateACW(Node root, int n) {

		if (root == null || n<=0) {
			return;
		}

		int size=size(root);
		if(n==size){
			//no need to rotate, as it will be the same
			System.out.println("List after rotating");
			print(root);
			return;			
		}
		
		if (n > size) {
			n=n%size;
		}

		System.out.println("List Before rotating");
		print(root);

		Node ptr = root;
		Node ptr1 = null;

		while (n-- > 0) {
			ptr1 = ptr;
			ptr = ptr.getLink();
		}

		Node temp = ptr;

		while (temp.getLink() != null) {
			temp = temp.getLink();
		}

		temp.setLink(root);
		ptr1.setLink(null);
		root = ptr;

		System.out.println("List after rotating");
		print(root);

	}
	
	
	/**
	 * Helper functions for LinkedList
	 */
	public void add(Node ptr, int data) {
		if (ptr == null) {
			System.out.println("Always null ?");
			ptr = new Node(data);
		} else {
			Node newptr = ptr;
			while (newptr.getLink() != null) {
				newptr = newptr.getLink();
			}
			newptr.setLink(new Node(data));
			newptr.getLink().setLink(null);
		}
	}

	public void print(Node ptr) {

		if (ptr == null) {
			return;
		}
		Node ptr1 = ptr;
		System.out.print(ptr1.getData() + "->");
		while ((ptr1 = ptr1.getLink()) != null) {
			System.out.print(ptr1.getData() + "->");
		}
		System.out.println("/n");

	}

	public int size(Node ptr) {

		if (ptr == null) {
			return -1;
		}
		Node ptr1 = ptr;
		int i = 1;
		while ((ptr1 = ptr1.getLink()) != null) {
			i++;
		}
		return i;
	}
	
	/**
	 * static inner class for LinkedList Data Structure
	 */
	private static class Node{
		 private int data;
		 private Node link; 		 
		    
		    Node(){
		    	    	
		    }
		    
		    Node(int data){
		    	//mergedList=new Node();
		        this.setData(data);
		        this.setLink(null);       
		    }
		    
		    public int getData(){
		        return this.data;
		    }
		      
		    public Node getLink(){
		        return this.link;
		    }
		    
		    public void setData(int data){
		        this.data=data;
		    }       
		    
		    public void setLink(Node link){
		        this.link=link;
		    }  
	}
	
}

Given a singly linked list swap every two nodes

Java program to swap every two nodes in a LinkedList e.g. 1->2->3->4->5->6 should become 2->1->4->3->6->5
/**
 * @author vikky.agrawal
 */

public class LinkedList {

	Node node = null;
	

	public static void main(String[] args) {

		LinkedList list = new LinkedList();
		list.operations();

	}

	public void operations() {

		this.node = new Node(10);

		for (int i = 1; i < 6; i++) {
			add(node, (int) (Math.random() * 100));
		}
		this.swap(node);
	}
	
	/**
	 * Given a singly linked list, swap every two nodes
	 * e.g. 1->2->3->4->5->6 should become 2->1->4->3->6->5
	 */
	
	public void swap(Node root){
		
		if(root == null){
			return;
		}
		
		System.out.println("before swap : ");
		print(root);
		
		
		Node temp=root;
		while(temp!=null && temp.getLink()!=null){
			int data=temp.getData();
			temp.setData(temp.getLink().getData());
			temp.getLink().setData(data);
			temp=temp.getLink().getLink();
		}
		System.out.println("After swap");
		print(root);
		
	}
	
	
	/**
	 * Helper functions for LinkedList
	 */
	public void add(Node ptr, int data) {
		if (ptr == null) {
			System.out.println("Always null ?");
			ptr = new Node(data);
		} else {
			Node newptr = ptr;
			while (newptr.getLink() != null) {
				newptr = newptr.getLink();
			}
			newptr.setLink(new Node(data));
			newptr.getLink().setLink(null);
		}
	}

	public void print(Node ptr) {

		if (ptr == null) {
			return;
		}
		Node ptr1 = ptr;
		System.out.print(ptr1.getData() + "->");
		while ((ptr1 = ptr1.getLink()) != null) {
			System.out.print(ptr1.getData() + "->");
		}
		System.out.println("/n");

	}

	public int size(Node ptr) {

		if (ptr == null) {
			return -1;
		}
		Node ptr1 = ptr;
		int i = 1;
		while ((ptr1 = ptr1.getLink()) != null) {
			i++;
		}
		return i;
	}
	
	/**
	 * static inner class for LinkedList Data Structure
	 */
	private static class Node{
		 private int data;
		 private Node link; 		 
		    
		    Node(){
		    	    	
		    }
		    
		    Node(int data){
		    	//mergedList=new Node();
		        this.setData(data);
		        this.setLink(null);       
		    }
		    
		    public int getData(){
		        return this.data;
		    }
		      
		    public Node getLink(){
		        return this.link;
		    }
		    
		    public void setData(int data){
		        this.data=data;
		    }       
		    
		    public void setLink(Node link){
		        this.link=link;
		    }  
	}
	
}

LinkedList : print middle element and print nth element from last


Java program having functions to print middle element of linked list(using slow and fast pointers) and printing nth element from last of linked list.

/**
 * @author vikky.agrawal
 * Link List print middle element | print nth element from last
 */

public class LinkedList {

	Node node = null;
	

	public static void main(String[] args) {

		LinkedList list = new LinkedList();
		list.operations();

	}

	public void operations() {

		this.node = new Node(10);

		for (int i = 1; i < 6; i++) {
			add(node, (int) (Math.random() * 100));
		}
		System.out.println("Middle in case of even no of elements:");		
		printMiddle(node);
		add(node, 65);
		System.out.println("Middle in case of odd no of elements:");
		printMiddle(node);
		printNthFromLast(node, 5);
	}
	
	
	//Print Nth element from last for given value of N	
	
	
	public void printNthFromLast(Node root, int n) {

		int i = n;
		if (root == null) {
			return;
		}

		if (i > size(root)) {
			System.out.println("Not enough elements");
			return;
		}

		Node node = root;
		Node nodeback = root;

		while ((node.getLink() != null) && (--i > 0)) {
			node = node.getLink();
		}

		if (node.getLink() != null) {
			while (node.getLink() != null) {
				nodeback = nodeback.getLink();
				node = node.getLink();
			}
		}

		System.out.println("N = " + n + " element from last is :"
				+ nodeback.getData());

	}

	/**
	 * Print middle element using slow and fast pointers.
	 */

	public void printMiddle(Node root) {
		if (root == null) {
			return;
		}

		System.out.println("Linked list is ");
		print(root);

		Node hare = null;
		Node tortoise = null;
		boolean temp = false;
		if (size(root) % 2 == 0)
			temp = true;

		if (temp) {
			hare = root.getLink();
			tortoise = root;
		} else {
			hare = root;
			tortoise = root;
		}

		while (hare != null && hare.getLink() != null) {
			hare = hare.getLink().getLink();
			tortoise = tortoise.getLink();
		 }
		if (temp) {
			System.out.println("Middle elements :" + tortoise.getData()
					+ " and " + tortoise.getLink().getData());
		} else {
			System.out.println("Middle element is :" + tortoise.getData());
		 }
	 }


	
	
	/**
	 * Helper functions for LinkedList
	 */
	public void add(Node ptr, int data) {
		if (ptr == null) {
			System.out.println("Always null ?");
			ptr = new Node(data);
		} else {
			Node newptr = ptr;
			while (newptr.getLink() != null) {
				newptr = newptr.getLink();
			}
			newptr.setLink(new Node(data));
			newptr.getLink().setLink(null);
		 }
	 }

	public void print(Node ptr) {

		if (ptr == null) {
			 return;
		}
		Node ptr1 = ptr;
		System.out.print(ptr1.getData() + "->");
		while ((ptr1 = ptr1.getLink()) != null) {
			System.out.print(ptr1.getData() + "->");
		}
		System.out.println("/n");

	 }

	public int size(Node ptr) {

		if (ptr == null) {
			return -1;
		}
		Node ptr1 = ptr;
		int i = 1;
		while ((ptr1 = ptr1.getLink()) != null) {
			i++;
		}
		return i;
	}

	
	/**
	 * static inner class for LinkedList Data Structure
	 */
	private static class Node{
		 private int data;
		 private Node link; 		 
		    
		    Node(){
		    	    	
		    }
		    
		    Node(int data){
		    	//mergedList=new Node();
		        this.setData(data);
		        this.setLink(null);       
		    }
		    
		    public int getData(){
		        return this.data;
		    }
		      
		    public Node getLink(){
		        return this.link;
		    }
		    
		    public void setData(int data){
		        this.data=data;
		    }       
		    
		    public void setLink(Node link){
		        this.link=link;
		    }  
	}
	
}

Sunday 1 March 2015

Selection sort in java

Selection sort finds the next minimum in array and replaces it with current index element while iterating through the array.
At the end of the loop array gets sorted.

Following program implements Selection sort in java.

/**
 * @author vikky.agrawal
 *
 */
public class SelectionSort {

    int[] arr;

    SelectionSort() {
        arr = new int[] { 5, 3, 1, 2, 9, 8 };
    }
    
    /**
     * @param args
     */
    public static void main(String[] args) {
        SelectionSort obj = new SelectionSort();
        obj.operate();

    }
    
    public void operate(){

        System.out.println("Array before sortings: ");
        printArray();
        selectionSort(arr);

        System.out.println("Sorted array : ");
        printArray();
    }
    
    /**
     * Not a stable sort
     * O(n^2)
     */
    public void selectionSort(int[] arr){
        
        int length=arr.length;
        for(int i=0; i<length; i++){
            //find the next min and swap
            int min=arr[i];
            int index=i;
            for(int j=i+1; j<length; j++ ){
                if(arr[j]<min){
                    min=arr[j];
                    index=j;
                }
            }
        
            if(index!=i){
                int temp=arr[i];
                arr[i]=arr[index];
                arr[index]=temp;
            }
                    
        }
    }

    public void printArray(){
        for (int a : arr) {
            System.out.print(a + " ");
        }
        System.out.println();
    }
}

Complexity analysis:
Complexity of Selection sort is O(n^2), since array is iterated and for each iteration minimum element is identified.
For the first element n-1 element compared,for second n-2 elements compared and so on.
So total time taken : (n-1)+(n-2)+(n-3)+.....1 = O(n^2) (worst case and best case)

Bubble Sort in java

Bubble sort is a comparison sort in which each element is compared with its adjacent element and swapped if they are in wrong order.
While iterating through the  array if there are no swaps then we can stop the loop, since no swap will mean array is sorted.
Following program implements Bubble sort in java.

/**
 * @author vikky.agrawal
 *
 */
public class BubbleSort {
    
    int[] arr;

    BubbleSort() {
        arr = new int[] { 5, 3, 1, 2, 9, 8 };
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        BubbleSort obj = new BubbleSort();
        obj.operate();
        
    }
    
    public void operate(){
        System.out.println("Array before sorting : ");
        printArray();
        
        bubbleSort(arr);
        
        System.out.println("Sorted array : ");
        printArray();
    }
 
    /**
     * stable sort
     * O(n^2)
     */
    
    public void bubbleSort(int[] arr){
        
        int length=arr.length;
        for(int i=0; i < length; i++){
          boolean swap=false;
            for(int j=(length-1); j&gt;i;j-- ){
                if(arr[j] < arr[j-1]){
                    int temp=arr[j-1];
                    arr[j-1]=arr[j];
                    arr[j]=temp;
                    swap=true;
                }
            }
            if(!swap){
                //If there is not even a single swap then break the loop;
                //Since each element is being compared and if no swapping then it means, array is sorted now.
                break;
            }            
        }
        
    }
    
    public void printArray(){
        for (int a : arr) {
            System.out.print(a + "");
        }
        System.out.println();
    }
}

Complexity analysis:
Complexity of Bubble sort is O(n^2), since array is iterated and for each iteration elements compared with adjacent elements.
For the first element n-1 element compared,for second n-2 elements compared and so on.
So total time taken : (n-1)+(n-2)+(n-3)+.....1 = O(n^2)(worst case)

In case array already sorted then loop only iterates once,
hence taking total time =O(n) (Best case).