/**
 * A class containing various methods for sorting 
 * integers in an array in increasing order.
 * 
 * Not all of this was developed or discussed in lectures;
 * the ones you should be most familiar with: insertionSort()
 * and selectionSort().
 * 
 * Note that the methods keep track of, and display, the number of 
 * comparisons and swaps performed.
 * 
 * (Thanks to Jen and Faye, my fellow instructors, for putting the
 * first versions of this together.)
 * 
 */

public class Sorting {
  
  /**
   * A helper method to display the contents of an array.
   */
  public static void displayList(int [] list) {
    for ( int i = 0; i< list.length; i++) {
       System.out.print(list[i] + " ");
    }
    System.out.println();
  }
  
 
  
  /**
   * Selection sort. 
   * Go up the array one by one: at each step, look at all the numbers 
   * in front of you (at a higher index) and select  the smallest. 
   * Swap this smallest with the array cell you are currently at. 
   * 
   * Notice that this keeps the portion of the array that
   * is behind you sorted, so when you get to the end... voila!
   */
  
  public static void selectionSort(int [] list) {
    int temp = 0;
    int comparisons = 0;
    int swaps = 0;
    
    // while the section in front of us is not empty
    for (int i = 0; i < list.length - 1; i++) {
      int smallest = i;
      // select the smallest item from this section
      for (int j = i + 1; j < list.length; j ++) {
        if (list[j] < list[ smallest] ) {
          smallest = j;
        }
        comparisons ++;
      }
      if (smallest != i) {
        
        // swap it with the current position
        swaps++;
        temp = list[i];
        list[i] = list[smallest];
        list[smallest] = temp;
      }
      // to see how the front part of the array takes shape,
      // uncomment the following line:
      // displayList(list);
      
   }
    displayList(list);
    System.out.println("Comparisons: " + comparisons + " Swaps: " + swaps);
  }
  
  
  /** 
   * Insertion sort:
   * Go up the array one by one: at each step, everything behind you 
   * (index numbers lower than where you  are at) is sorted already. 
   * Take the current value in the array (call it v), and going backwards 
   * from where you are, find the position where v goes (that is right after the 
   * first cell that has something not greater than v) and stick it in there. 
   * Make room for this value by shifting the contents - between where v goes 
   * and where you are - up by one cell. 
   * One way of finding where v goes and  "shifting the contents" at the same 
   * time is to keep swapping v with the  contents of the cell below it as you go 
   * backward (that's what the while loop is doing).
   */
  
  public static void insertionSort(int[] list) {
    int swaps = 0 ;
    int comps = 0;
    for (int i = 0; i < list.length; i++) {
      int j = i;
      comps++;
      
      // Going backwards, compare element i with the elements
      // in the sorted part of the list [0..i-1]
      // and insert it where it needs to go. Do this by swapping 'v'
      // with the contents of the cell below it until the cell below it 
      // contains a number that's less than or equal to 'v'.
      while (j != 0 && list[j] < list[j - 1] ) {
        comps ++;
        // swap element at j with element at j-1 -  now 'v' is in j-1, and
        // will keep going down until the loop stops.
        int temp = list[j];
        list[j] = list[j-1];
        list [j-1] = temp;
        swaps++;
        j--;
        
      }
      // to see how 'v' migrates down, uncomment the following line and list
      // will be displayed every time through th loop
      //displayList(list);
    }
    displayList(list);
    System.out.println("Comparisons: " + comps + " Swaps: " + swaps);
    
  }  
   /**
   * Bubble sort algorithm:
   * - 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 temp = 0;
    int comparisons = 0;
    int swaps = 0;
    
    for (int j = 0; j < list.length; j++) {
      for (int i = 0; i < list.length - 1; i ++) {
        comparisons ++;
        if (list[i] > list[i+1]) {
          temp = list[i];
          list[i] = list[i+1];
          list[i+1] = temp;
          swaps ++;
        }
      }
    }
    displayList(list);
    System.out.println("Comparisons: " + comparisons + " Swaps: " + swaps);
  }
  
  /* Bubble sort (improved!):
   * - stop when the list is sorted.
   * Don't compare with elements that are already 
   * 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); 
    
  }
}

