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 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
   * 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); 
    
  }
  
  /**
   * Sort the items in array list in increasing
   * order.
   */
  public static void selectionSort(int [] list) {
    int temp = 0;
    int comparisons = 0;
    int swaps = 0;
    // while the unknown section is not empty
    for (int i = 0; i < list.length - 1; i++) {
      int smallest = i;
      // select the smallest item from the unknown section
      // and put it where it belongs.
      for (int j = i + 1; j < list.length; j ++) {
        if (list[j] < list[ smallest] ) {
          smallest = j;
        }
        comparisons ++;
      }
      if (smallest != i) {
        swaps++;
        temp = list[i];
        list[i] = list[smallest];
        list[smallest] = temp;
      }
    }
    displayList(list);
    System.out.println("Comparisons: " + comparisons + " Swaps: " + swaps);
    
  }
  /** 
   * 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) {
    int swaps = 0 ;
    int comps = 0;
    for (int i = 0; i < list.length; i++) {
      int j = i;
      comps++;
      
      // 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] ) {
        comps ++;
        // swap element at j with element at j-1
        int temp = list[j];
        list[j] = list[j-1];
        list [j-1] = temp;
        swaps++;
        j--;
      }
    }
    displayList(list);
    System.out.println("Comparisons: " + comps + " Swaps: " + swaps);
    
  }
  
}

