// This program has a method sort that can sort a LinkedList of Strings. It // uses a mergesort algorithm. Method main tests it by constructing two // LinkedLists of Strings. It compares the time used by this sort versus // the standard Collections.sort. // // The program includes a "trial run" of the sorting calls prior to the timed // executions. Java performs some optimizations that distort the times without // these trial runs. import java.util.*; import java.util.Queue; public class Sorter { public static void main(String[] args) { // make 2 copies for the comparision (list1, list2) and 2 copies // for the trial runs (list3, list4) LinkedList list1 = new LinkedList(); LinkedList list2 = new LinkedList(); LinkedList list3 = new LinkedList(); LinkedList list4 = new LinkedList(); fill(list1, list2, list3, list4); // perform trial runs to warm up the JVM sort(list3); Collections.sort(list4); runTests(list1, list2); checkMatch(list1, list2); } // make a random list of strings and put in each of the lists public static void fill(LinkedList list1, LinkedList list2, LinkedList list3, LinkedList list4) { int n = 1000000; Random r = new Random(); for (int i = 0; i < n; i++) { String text = "some text with #" + r.nextInt(2 * n); list1.add(text); list2.add(text); list3.add(text); list4.add(text); } } // Runs and times this sort and built-in sort using list1, list2 public static void runTests(LinkedList list1, LinkedList list2) { // run and time our sort long start = System.currentTimeMillis(); sort(list1); double elapsed1 = (System.currentTimeMillis() - start)/1000.0; System.out.println("linked list sort took " + elapsed1 + " seconds"); System.out.println(); // run and time built-in sort start = System.currentTimeMillis(); Collections.sort(list2); double elapsed2 = (System.currentTimeMillis() - start)/1000.0; System.out.println("collections sort took " + elapsed2 + " seconds"); System.out.println(); System.out.println("Ratio = " + elapsed1 / elapsed2); } // compares the lists and reports whether they match public static void checkMatch(LinkedList list1, LinkedList list2) { Iterator i1 = list1.iterator(); Iterator i2 = list2.iterator(); boolean match = true; boolean stable = true; while (match && i1.hasNext() && i2.hasNext()) { String s1 = i1.next(); String s2 = i2.next(); if (!s1.equals(s2)) { match = false; } if (s1 != s2) { stable = false; } } match = match && !i1.hasNext() && !i2.hasNext(); if (!match) { System.out.println("lists don't match"); } else if (!stable) { System.out.println("lists match, but sort is not stable"); } else { System.out.println("lists match and sort is stable"); } } // post: list is in sorted (nondecreasing) order public static void sort(Queue list) { if (list.size() > 1) { Queue half1 = new LinkedList(); Queue half2 = new LinkedList(); int size1 = list.size() / 2; int size2 = list.size() - size1; for (int i = 0; i < size1; i++) { half1.add(list.remove()); } for (int i = 0; i < size2; i++) { half2.add(list.remove()); } sort(half1); sort(half2); mergeInto(list, half1, half2); } } // pre : result is empty; list1 is sorted; list2 is sorted // post: result contains the result of merging the sorted lists; // list1 is empty; list2 is empty public static void mergeInto(Queue result, Queue list1, Queue list2) { while (!list1.isEmpty() && !list2.isEmpty()) { if (list1.peek().compareTo(list2.peek()) <= 0) { result.add(list1.remove()); } else { result.add(list2.remove()); } } while (!list1.isEmpty()) { result.add(list1.remove()); } while (!list2.isEmpty()) { result.add(list2.remove()); } } }