public class Sorting {
  
  /**
   * Display the contents of the list.
   */
  public static void displayList(int[] list) {
    for(int i = 0; i < list.length; i++) {
      System.out.print(list[i] + " ");
    }
    System.out.println();
  }

  /**
   * Sort the items in an array in increasing
   * order.
   * 
   * Bubble sort:
   * - traverse the list comparing neighbouring
   *   elements
   * - move the smaller element into the lower
   * position
   * - repeat list.length times
   */
  public static void bubbleSort(int[] list) {
    int swaps = 0;
    int comps = 0;
    
    for(int j = 0; j < list.length; j++) {
      for(int i = 0; i < list.length - 1; i++) {
        
        // compare adjacent elements
        if(list[i] > list[i+1]) {
          
          // swap
          int temp = list[i];
          list[i] = list[i+1];
          list[i+1] = temp;
          swaps++;
        }
        comps++;
      }
    }
    displayList(list);
    
    System.out.println("Swaps: " + swaps 
                         + " Comparisons: " + comps); 
  }
  
  /* Bubble sort (improved!):
   * - stop when the list is sorted
   * - don't compare with elements that are
   * definitely in their sorted position
   */
  public static void bubbleSort2(int[] list) {
    boolean didSwap = true;
    int j = 0;
    int swaps = 0;
    int comps = 0;
    
    while(didSwap) {
      didSwap = false;
      for(int i = 0; i < list.length - 1 - j; i++) {
        
        // compare adjacent elements
        if(list[i] > list[i+1]) {
          didSwap = true;
          // swap
          int temp = list[i];
          list[i] = list[i+1];
          list[i+1] = temp;
          swaps++;
        }
        comps++;
      }
      j++;
    }
    displayList(list);
    System.out.println("Swaps: " + swaps 
                         + " Comparisons: " + comps); 

  }

  /** 
   * Insertion sort:
   * - pick an element from the unsort section of
   * the list
   * - insert it into its proper position in the
   * sorted part of the list
   * - repeat for all elements
   */
  public static void insertionSort(int[] list) {
   
    for(int i = 0; i < list.length; i++) {
      int j = i;
      
      // compare element i with the elements
      // in the sorted part of the list [0..i-1]
      // and insert it into the sorted part of the list
      while(j != 0 && list[j] < list[j-1] ){
      
        // swap element at j with element at j-1
        int temp = list[j];
        list[j] = list[j-1];
        list[j-1] = temp;
        j--;
      }
    }
  }
  
  /**
   * Selection sort:
   * - find the smallest element, put it in position 0
   * - find the 2nd smallest, put it in position 1
   * ...
   * - find the nth smallest, put it in position n-1
   */
  public static void selectionSort(int[] list) {
   
    for(int i = 0; i < list.length; i++) {
      int smallestIndex = i;
      
      // compare i with unsorted elements:
      // [i to list.length-1]
      for(int j = i+1; j < list.length; j++) {
        if(list[smallestIndex] > list[j]) {
          smallestIndex = j;
        }
      }
      
      // put the element at smallestIndex into
      // its proper position in the sorted section
      int temp = list[i];
      list[i] = list[smallestIndex];
      list[smallestIndex] = temp;
      
      displayList(list);
    }
    
  }
}

