// This program compares the runtime of various sorting algorithms import java.util.*; // for Random import java.util.function.*; public class Sorting { private static final Random RAND = new Random(); public static void main(String[] args) { System.out.println("Merge Sort"); testSort(Sorting::mergeSort); System.out.println("QuickSort"); testSort(Sorting::quickSort); } public static void testSort(Consumer sortFunc) { int length = 10000; // initial length of array to sort int runs = 12; // how many times to double length for (int i = 0; i < runs; i++) { int[] a = createRandomArray(length); // perform a sort and time how long it takes long startTime = System.currentTimeMillis(); // sort here sortFunc.accept(a); long endTime = System.currentTimeMillis(); ensureSorted(a); System.out.printf("%10d elements => %6d ms \n", length, endTime - startTime); length *= 2; // double size of array for next time } } // Rearranges the elements of a into sorted order using // the selection sort algorithm. public static void selectionSort(int[] a) { for (int i = 0; i < a.length - 1; i++) { // look for minimum element int minIndex = i; for (int j = i + 1; j < a.length; j++) { if (a[j] < a[minIndex]) { minIndex = j; } } if (minIndex != i) { swap(a, i, minIndex); } } } // Rearranges the elements of a into sorted order using // the insertion sort algorithm. public static void insertionSort(int[] a) { for (int i = 1; i < a.length; i++) { // insert element at index i into subarray [0, i-1] int elementToInsert = a[i]; int j = i; // loop backwards and shift values over until the insertion // point is found while (j > 0 && elementToInsert < a[j - 1]) { a[j] = a[j - 1]; j--; } // found the insertion point a[j] = elementToInsert; } } // Rearranges the elements of a into sorted order using // the bubble sort algorithm. public static void bubbleSort(int[] a) { boolean sorted = false; while (!sorted) { sorted = true; for (int i = 0; i < a.length - 1; i++) { if (a[i] > a[i + 1]) { // found inversion. swap. sorted = false; swap(a, i, i + 1); } } } } // Rearranges the elements of a into sorted order using the // merge sort algorithm. public static void mergeSort(int[] a) { // base case: lists of length 0 and 1 are already sorted! if (a.length > 1) { int[] left = Arrays.copyOfRange(a, 0, a.length / 2); int[] right = Arrays.copyOfRange(a, a.length / 2, a.length); // sort right, left mergeSort(left); mergeSort(right); merge(a, left, right); } } // Merges the contents of sorted lists left and right into result, // preserving sorted order. // pre: result.length = left.length + right.length; left is sorted; right is // sorted private static void merge(int[] result, int[] left, int[] right) { int leftIndex = 0; int rightIndex = 0; for (int i = 0; i < result.length; i++) { if (rightIndex >= right.length || leftIndex < left.length && left[leftIndex] < right[rightIndex]) { result[i] = left[leftIndex]; leftIndex++; } else { result[i] = right[rightIndex]; rightIndex++; } } } // Rearranges the elements of a into sorted order using the // quick sort algorithm. public static void quickSort(int[] list) { quickSort(list, 0, list.length - 1); } // post: elements low through high of given list are in sorted // (nondecreasing) order public static void quickSort(int[] list, int low, int high) { // uses recursive quicksort to sort elements low through high; // base case is a list of 0 or 1 elements, which requires no // sorting; in recursive case, the list is partitioned using a // pivot value and the two resulting lists are recursively // sorted if (low < high) { int pivotIndex = partition(list, low, high); quickSort(list, low, pivotIndex - 1); quickSort(list, pivotIndex + 1, high); } } // post: picks a random spot of the list as a "pivot" to partition // the list into two sublists: all those values less than or // equal to the pivot appearing first followed by the pivot // followed by all those values greater than the pivot; // places the pivot value between the two sublists and // returns the index of the pivot value private static int partition(int[] list, int low, int high) { // pick a random spot for the pivot int spot = low + (int) ((high - low + 1) * Math.random()); // put the pivot at the front swap(list, low, spot); // remember pivot int pivot = list[low]; // loop invariant: list divided into 3 parts: values <= pivot, // unknown values, values > pivot int index1 = low + 1; // index of first unknown value int index2 = high; // index of last unknown value while (index1 <= index2) // while some values still unknown if (list[index1] <= pivot) { index1++; } else if (list[index2] > pivot) { index2--; } else { swap(list, index1, index2); index1++; index2--; } // put the pivot value between the two sublists and return its // index swap(list, low, index2); return index2; } // pre : 0 <= index1, index2 < list.length // post: Values of list[x] and list[y] are exchanged. private static void swap(int[] list, int index1, int index2) { int temp = list[index1]; list[index1] = list[index2]; list[index2] = temp; } // Creates an array of the given length, fills it with random // non-negative integers, and returns it. public static int[] createRandomArray(int length) { int[] a = new int[length]; for (int i = 0; i < a.length; i++) { a[i] = RAND.nextInt(1000000000); } return a; } // Checks whether the given array is in sorted order. // Throws an IllegalStateException if it is not. public static void ensureSorted(int[] a) { for (int i = 0; i < a.length - 1; i++) { if (a[i] > a[i + 1]) { throw new IllegalStateException("array not sorted at index " + i); } } } }