import java.util.*;

public class Sort {
 
  /** Display the contents of the list. */
  public static void print(int[] list) {
    for (int i = 0; i < list.length; i++) {
      System.out.print(list[i] + " ");
    }
    System.out.println();
  }
  
  /**
   * Bubble sort:
   * 
   * - traverse the list comparing pairs of elements
   * - move the larger element into the higher position
   * - repeat list.length - 1 times
   */ 
  public static void bubbleSort(int[] list) {
    int comps = 0;
    int swaps = 0;
    
    for (int j = 0; j < list.length - 1; j++) {
      for (int i = 0; i < list.length - 1; i++) {
        
        // count the number of comparions
        comps++;
        
        // compare neighbouring elements
        if (list[i] > list[i + 1]) {
          
          // swap i with i + 1
          int temp = list[i];
          list[i] = list[i + 1];
          list[i + 1] = temp;
          
          // count the number of swaps
          swaps++;
        }
      }
    }
    
    print(list);
    System.out.println("Comparisons: " + comps 
                         + " Swaps: " + swaps);
  }
  
  /**
   * Improved bubble sort:
   *  - stop sorting when the array becomes sorted
   *  - do not compare elements of the array with
   *    the elements that are in their correct sorted
   *    position
   */ 
  public static void bubbleSort2(int[] list) {
    Date start = new Date();
    int comps = 0;
    int swaps = 0;
    boolean didSwap = true;
    
    // didSwap tracks whether any elements of the array
    // were swapped during the last iteration of the loop.
    // If no elements were swapped, the the array is 
    // sorted, so we can stop.
    for (int j = 0; j < list.length - 1 && didSwap; j++) {
      didSwap = false;
      
      // at this point, j elements are already in their
      // correct sorted position, so we do not compare
      // with the last j elements in the list
      for (int i = 0; i < list.length - 1 - j ; i++) {
        
        // count the number of comparions
        comps++;
        
        // compare neighbouring elements
        if (list[i] > list[i + 1]) {
          
          didSwap = true;
          
          // swap i with i + 1
          int temp = list[i];
          list[i] = list[i + 1];
          list[i + 1] = temp;
          
          // count the number of swaps
          swaps++;
        }
        
      }
    }

    Date end = new Date();
    System.out.println("Time elapsed = " 
                          + (end.getTime() - start.getTime())
                         + " milliseconds.");
    
    //print(list);
    System.out.println("Comparisons: " + comps 
                         + " Swaps: " + swaps);
  }
  
   /**
   * Insertion sort:
   * - pick an element and put it into its correct
   * position in the sorted part of the list
   * - repeat list.length times
   */ 
  public static void insertionSort(int[] list) {
    Date start = new Date();
    int comps = 0;
    int swaps = 0;
    
    for (int i = 1; i < list.length; i++) {
      
      int j = i;
      
      // compare i with sorted elements and insert it
      // sorted elements: [0..i-1]
      while(j > 0 && list[j] < list[j-1]) {
        
        // swap j with j-1
        int temp = list[j];
        list[j] = list[j-1];
        list[j-1] = temp;
        
        swaps++;
        comps++; // counting loop condition when true
        
        j--;
      }
      
      comps++; // counting loop condition when false
      
    }
    
    Date end = new Date();
    System.out.println("Time elapsed = " 
                          + (end.getTime() - start.getTime())
                         + " milliseconds.");
    
    //print(list);
    System.out.println("Comparisons: " + comps 
                         + " Swaps: " + swaps);
  }
  
  /**
   * Selection sort:
   * - pick smallest #, put it in position 0
   * - pick 2nd smalllest #, put it in position 1
   * ...
   * - pick list.length smallest, put it in position list.length -1
   */ 
  public static void selectionSort(int[] list) {
    Date start = new Date();
    int comps = 0;
    int swaps = 0;
   
    // for every element in the list
    for (int i = 0; i < list.length - 1; i++) {
      int smallestIndex = i;
      
      // select the smallest element in the unknown area
      // [0..i-1] is sorted, [i..list.length-1] is unknown
      for (int j = i + 1; j < list.length; j++) {
        
        if (list[j] < list[smallestIndex]) {
          smallestIndex = j;
        }
        
        comps++;
      }
      
      // take the smallest element from unknown section,
      // put it into ith position.
      int temp = list[i];
      list[i] = list[smallestIndex];
      list[smallestIndex] = temp;
      
      swaps++;
      
    }
    Date end = new Date();
    System.out.println("Time elapsed = " 
                          + (end.getTime() - start.getTime())
                         + " milliseconds.");
    
    //print(list);
    System.out.println("Comparisons: " + comps 
                         + " Swaps: " + swaps);

  }
  
}