// by John P. Spurgeon /* Of course, “nonnumerical analysis” is a terribly negative name for this * field of study, and it would be much better to have a positive, descriptive term * which characterizes the subject. “Information processing” is too broad a * designation for the matter I am considering, and “programming techniques” * is too narrow. Therefore, I wish to propose analysis of algorithms as an appro- * priate name for the subject matter covered in these books; as explained more * fully in the books themselves, this name is meant to imply “the theory of the * properties of particular computer algorithms.” * * — DONALD E. KNUTH, The Art of Computer Programming, vol. 1 (1968) * * * Ernest Hemingway’s work is characterized by * direct, uncomplicated prose and a lack of arti- * fice. In his fiction, he describes only the tangible * truths: dialog, action, superficial traits. He does * not attempt to explain emotion; he leaves it alone. * This is not because Hemingway doesn’t want his * stories to convey feeling — quite the opposite: his * intent is to create a vacuum so that it might be * filled by the reader’s own experience. After all, * emotion is more easily felt than described with * words: * * I have tried to eliminate everything unneces- * sary to conveying experience to the reader so * that after he or she has read something it will * become a part of his or her experience and * seem actually to have happened. * * Hemingway’s prose is never showy, and his * syntax is almost obsessively conventional. The * short, unchallenging sentences and absence of * difficult words add a childlike quality to his ca- * dence. He assumes the role of naive observer, all * the better to draw his readers into the emotional * caos beneath. * * — ANGUS CROLL, If Hemingway Wrote JavaScript (2015) * * * In the late summer of that year we lived in a house in a village * that looked across the river and the plain to the mountains. * * — ERNEST HEMINGWAY, A Farewell to Arms (1929) */ // On 30 April 2018, this was at: // http://scribbledecobble.blogspot.com/2018/04/analysis-of-algorithms.html
/* In the last years of my twenty at the corporation, we built a house on a hill that looks across * the Sunset Highway and the Willamette Valley to town. I worked in the IT department back then. */ /* An arm is an upper limb of the body. * Arm or ARM may also refer to: * * Computing * * - ARM architecture, a RISC instruction set family * - ARM Holdings, a multinational company that designs the ARM computer processors * - Application Response Measurement, an open standard for diagnosing performance bottlenecks * - Abstract rewriting machine, a virtual machine * - Arm (software), a CLI status monitor for Tor * * Weaponry * * - Armaments or weapon, any device used with intent to inflict damage or harm * - Firearm, a portable gun * - Anti-radiation missile, a missile designed to detect and home in on an enemy radio emission source * * from https://en.wikipedia.org/wiki/Arm_(disambiguation) */ /* Edmund Callis Berkeley (February 22, 1909 – March 7, 1988) was an American computer scientist * who co-founded the Association for Computing Machinery (ACM) in 1947. His 1949 book Giant Brains, * or Machines That Think popularized cognitive images of early computers. He was also a social * activist who worked to achieve conditions that might minimize the threat of nuclear war. * * Berkeley received a BA in Mathematics and Logic from Harvard in 1930. He pursued a career as an * insurance actuary at Prudential Insurance from 1934–48, except for service in the United States * Navy during World War II. * * from https://en.wikipedia.org/wiki/Edmund_Berkeley */ /* The leaders of North and South Korea agreed on Friday to work to remove all nuclear weapons from the * Korean Peninsula and, within the year, pursue talks with the United States to declare an official end * to the Korean War, which ravaged the peninsula from 1950 to 1953. * * from “North and South Korea Set Bold Goals: A Final Peace and No Nuclear Arms” * by Choe Sang-Hun, The New York Times (April 27, 2018); accessed on 29 April 2018 at: * https://www.nytimes.com/2018/04/27/world/asia/north-korea-south-kim-jong-un.html */ /***********************************/ /* PROGRAM SOURCE CODE BEGINS HERE */ /***********************************/ import java.lang.Iterable; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.ArrayList; import java.util.List;
/**************/ /* INTERFACES */ /**************/ // Values comprise datasets. interface Labeled { String label(); } interface Dataset<E> extends Labeled { int size(); E getValue(int i); E lastAdded(); } interface ExtensibleDataset<E> extends Dataset<E> { void add(E element); } // Datasets yield fundamental metrics. interface IntegralMetrics extends Labeled { Long sum(); Long min(); Long max(); Double avg(); Double sd(); // standard deviation } // Fundamental metrics can be used to analyze algorithms. interface TimeAnalysis { IntegralMetrics elapsedTime(); } interface ComparisonAnalysis { IntegralMetrics comparisons(); } interface ExchangeAnalysis { IntegralMetrics exchanges(); } // Doers do. interface Searcher<E extends Comparable<E>> { int search(E element, List<E> list); } interface Sorter<E extends Comparable<E>> { List<E> sort(List<E> list); } interface Exchanger<E> { void exchange(List<E> list, int i, int j); } interface Permuter<E> { List<List<E>> allPermutationsOf(List<E> list); } interface Shuffler<E> { List<E> shuffle(List<E> list); } interface ReadonlyCounter { long getCount(); } interface Counter extends ReadonlyCounter { void increment(); } // Some types are mashups, such as doers that think too. interface ComparisonAlgorithmAnalysis extends TimeAnalysis, ComparisonAnalysis {} interface ExchangeSortingAnalysis extends ComparisonAlgorithmAnalysis, ExchangeAnalysis {} interface SearcherAnalyzer<E extends Comparable<E>> extends Searcher<E>, ComparisonAlgorithmAnalysis, ReadonlyCounter {} interface SorterAnalyzer<E extends Comparable<E>> extends Sorter<E>, ComparisonAlgorithmAnalysis, ReadonlyCounter {} interface ExchangeSorterAnalyzer<E extends Comparable<E>> extends SorterAnalyzer<E>, ExchangeSortingAnalysis {}
/*****************************************/ /* COUNTERS, COMPARATORS, AND EXCHANGERS */ /*****************************************/ class CounterMayThrowException implements Counter { private long count = 0; private long overflowCount = 0; private final boolean throwExceptionIfCounterOverflows; public CounterMayThrowException() { this(true); } public CounterMayThrowException(boolean throwExceptionIfCounterOverflows) { this.throwExceptionIfCounterOverflows = throwExceptionIfCounterOverflows; } public final long getCount() { return count; } public final long getOverflowCount() { return overflowCount; } public final void increment() { if (++count < 0) // Increment count first and then check the value. { count = 1; onOverflow(); } } protected void onOverflow() { if (throwExceptionIfCounterOverflows) throw new ArithmeticException("Counter overflowed."); if (++overflowCount < 0) throw new ArithmeticException("Overflow counter overflowed. (Wow!)"); } } final class ComparatorCounter<E> implements Comparator<E>, ReadonlyCounter { private final Comparator<E> comparator; private final Counter comparisonCounter = new CounterMayThrowException(); public ComparatorCounter(Comparator<E> comparator) { this.comparator = comparator; } public final int compare(E left, E right) { comparisonCounter.increment(); return comparator.compare(left, right); } public final long getCount() { return comparisonCounter.getCount(); } } final class ExchangerCounter<E> implements Exchanger<E>, ReadonlyCounter { private final Counter exchangeCounter = new CounterMayThrowException(); public final void exchange(List<E> list, int i, int j) { exchangeCounter.increment(); final E tmp = list.get(i); list.set(i, list.get(j)); list.set(j, tmp); } public final long getCount() { return exchangeCounter.getCount(); } }
/********************************/ /* EXTENSIBLE DATASET + METRICS */ /********************************/ final class ExtensibleDatasetMetrics implements ExtensibleDataset<Long>, IntegralMetrics { private final String label; private List<Long> values = new ArrayList<Long>(); private Long lastAdded = null; private Long sum = null; private Long min = null; private Long max = null; private Double sd; private boolean isDirty = false; public ExtensibleDatasetMetrics(String label) { this.label = label; } public final String label() { return label; } public final int size() { return values.size(); } public final Long getValue(int i) { return values.get(i); } public final Long lastAdded() { return lastAdded; } public final Long sum() { return sum; } public final Long max() { return max; } public final Long min() { return min; } public final Double avg() { return ((double)sum) / values.size(); } public final Double sd() { if (isDirty) { sd = computeStdDev(values, this.avg()); isDirty = false; } return sd; } public void add(Long value) { isDirty = true; values.add(value); lastAdded = value; if (sum == null) min = max = sum = value; else { sum += value; if (value < min) min = value; else if (value > max) max = value; } } private double computeStdDev(List<Long> values, double average) { final int n = values.size(); double sumOfSquares = 0; for (long value : values) { final double difference = value - average; sumOfSquares += difference * difference; } final double avgSquaredDifference = sumOfSquares / n; return Math.sqrt(avgSquaredDifference); } }
/* Doctrine and dogma are the enemies of good JavaScript. Beware of the overly * protective mentor; reject the dry and narrow confines of computer science * classes. Some developers thrive on rules and constraint, which is why there * is Java. If 25 famous authors wrote Java, the result would be more or less * the same every time. But JavaScript is much less prescriptive and appeals to * those who value creativity over predictability. * * —ANGUS CROLL, If Hemingway Wrote JavaScript (2015) */ /*********************************/ /* COMPARISON ALGORITHM ANALYZER */ /*********************************/ abstract class AbstractComparisonAlgorithmAnalyzer<E extends Comparable<E>> implements ComparisonAlgorithmAnalysis { private final ComparatorCounter<E> comparatorCounter; private long startCompareCount, startTime; private final ExtensibleDatasetMetrics timeData = new ExtensibleDatasetMetrics("Time"), compareData = new ExtensibleDatasetMetrics("Comparisons"); // Constructors protected AbstractComparisonAlgorithmAnalyzer() { this((E left, E right) -> left.compareTo(right)); } protected AbstractComparisonAlgorithmAnalyzer(Comparator<E> cmp) { this(new ComparatorCounter<E>(cmp)); } protected AbstractComparisonAlgorithmAnalyzer(ComparatorCounter<E> cmpCtr) { this.comparatorCounter = cmpCtr; } // Protected Operations protected final Comparator<E> getComparator() { return comparatorCounter; } protected final int compare(E left, E right) { return comparatorCounter.compare(left, right); } protected void doBeforeCallingMethod() { startCompareCount = comparatorCounter.getCount(); startTime = System.nanoTime(); } protected void doAfterMethodReturns() { timeData.add(System.nanoTime() - startTime); compareData.add(comparatorCounter.getCount() - startCompareCount); } // Public Operations public final long getCount() { return timeData.size(); } public final IntegralMetrics elapsedTime() { return timeData; } public final IntegralMetrics comparisons() { return compareData; } public String toString() { return this.getClass().getSimpleName(); } }
/************************/ /* ALL SORTS OF SORTERS */ /************************/ abstract class AbstractSorterAnalyzer<E extends Comparable<E>> extends AbstractComparisonAlgorithmAnalyzer<E> implements SorterAnalyzer<E> { // Constructors protected AbstractSorterAnalyzer() { super(); } protected AbstractSorterAnalyzer(Comparator<E> cmp) { super(cmp); } // Additional Operations protected abstract void applySortMethod(List<E> list); // SORTING ALGORITHM GOES HERE public final List<E> sort(List<E> list) { doBeforeCallingMethod(); // START COLLECTING DATA applySortMethod(list); // EXECUTE SORTING ALGORITHM doAfterMethodReturns(); // FINISH COLLECTING DATA return list; } } abstract class AbstractExchangeSorterAnalyzer<E extends Comparable<E>> extends AbstractSorterAnalyzer<E> implements ExchangeSorterAnalyzer<E> { // Additional Values private final ExchangerCounter<E> exchangerCounter = new ExchangerCounter<E>(); private long startExchangeCount; private final ExtensibleDatasetMetrics exchangeData = new ExtensibleDatasetMetrics("Exchanges"); // Constructors protected AbstractExchangeSorterAnalyzer() { super(); } protected AbstractExchangeSorterAnalyzer(Comparator<E> cmp) { super(cmp); } // Method Overrides protected final void doBeforeCallingMethod() { startExchangeCount = exchangerCounter.getCount(); super.doBeforeCallingMethod(); } protected final void doAfterMethodReturns() { super.doAfterMethodReturns(); exchangeData.add(exchangerCounter.getCount() - startExchangeCount); } // Additional Operations protected final void exchange(List<E> list, int i, int j) { exchangerCounter.exchange(list, i, j); } protected final ReadonlyCounter getExchangeCounter() { return exchangerCounter; } public final IntegralMetrics exchanges() { return exchangeData; } }
final class BubbleSorter<E extends Comparable<E>> extends AbstractExchangeSorterAnalyzer<E> { public BubbleSorter() { super(); } public BubbleSorter(Comparator<E> cmp) { super(cmp); } protected void applySortMethod(List<E> list) { final int n = list.size(); final ReadonlyCounter xCtr = getExchangeCounter(); for (int k = n - 1; k > 0; k--) // The next largest value bubbles up to its spot each pass, { // so we don't need to go all the way to the end each time. final long xCt = xCtr.getCount(); // Note the current exchange count; we'll use it later. for (int i = 0; i < k; i++) // We'll compare successive pairs of elements beginning at { // at index zero, proceeding as far to the right as necessary. final int j = i + 1; // The index of left is i. Let j be the index of right. final E left = list.get(i); // Get the value of left at position i. final E right = list.get(j); // Get the value of right at position j. if (compare(left, right) > 0) // If left is greater than right, exchange(list, i, j); // then exchange. } // Increment i and compare the next pair of elements. if (xCt == xCtr.getCount()) // If we didn't make any more exchanges, then return; // the list must be sorted, so return to whence you came. } // Repeat until done. (Bubble up the next largest value.) } // Done: Shake a cocktail and celebrate! } final class SelectionSorter<E extends Comparable<E>> extends AbstractExchangeSorterAnalyzer<E> { public SelectionSorter() { super(); } public SelectionSorter(Comparator<E> cmp) { super(cmp); } private int indexOfMin(List<E> list, int i, int j) { int indexOfMin = i; E min = list.get(indexOfMin); for (int k = i + 1; k <= j; k++) { final E curr = list.get(k); if (compare(curr, min) < 0) { min = curr; indexOfMin = k; } } return indexOfMin; } protected void applySortMethod(List<E> list) { final int n = list.size(); // Let n be the number of elements to sort. final int j = n - 1; // Let j be the index of the last element. for (int i = 0; i < j; i++) // Consider each successively smaller tail of the list: { // final int k = indexOfMin(list, i, j); // Find the index of the smallest element in the tail. if (k != i) // If the element is not at the front of the tail, exchange(list, i, k); // then exchange it with the head of the tail. } // Repeat until the tail is no more. } // Done. }
final class InsertionSorter<E extends Comparable<E>> extends AbstractExchangeSorterAnalyzer<E> { public InsertionSorter() { super(); } public InsertionSorter(Comparator<E> cmp) { super(cmp); } protected void applySortMethod(List<E> list) { final int n = list.size(); // Let n be the number of elements to insert in order. for (int i = 1; i < n; i++) // Insert elements one by one into a sorted part. { // The next element to insert, if any, is at index i. final E right = list.get(i); // Let right be the value of the element at index i. for (int j = i - 1; j >= 0; j--) // Start just to the left of right and move left. { // The next already inserted element is at index j. final E left = list.get(j); // Let left be the value of the element at index j. if (compare(right, left) < 0) // If right is less than left, then exchange(list, j, j + 1); // exchange left and right (right must be at j + 1); else // otherwise, break; // right is inserted. Go insert the next element. } // Consider the next already inserted element, if any. } // Insert the next element until all are inserted. } // Done. } final class QuickSorter<E extends Comparable<E>> extends AbstractExchangeSorterAnalyzer<E> { public QuickSorter() { super(); } public QuickSorter(Comparator<E> cmp) { super(cmp); } private void quickSort(List<E> list, int i, int j) { if (j <= i) return; // (There might be nothing to do.) int p = i; // Let p be the index of the pivot. final E left = list.get(p); // Let left be the value of the pivot. for (int k = i + 1; k <= j; k++) // Consider each element to the right of the pivot. { // final E right = list.get(k); // Let right be the value under consideration. if (compare(right, left) < 0) // If right is less than left, then { // move right to the other side of left: if (k > p + 1) // If right isn't already next to left, then exchange(list, p + 1, k); // move right immediately to the right of left. exchange(list, p, p + 1); // Exchange left and right. p++; // Increment the index of the pivot. } // } // Consider the next element, if any. quickSort(list, i, p - 1); // Sort the elements to the left of the pivot. quickSort(list, p + 1, j); // Sort the elements to the right of the pivot. } // Done. protected void applySortMethod(List<E> list) { quickSort(list, 0, list.size() - 1); } } final class CollectionsSorter<E extends Comparable<E>> extends AbstractExchangeSorterAnalyzer<E> { public CollectionsSorter() { super(); } public CollectionsSorter(Comparator<E> cmp) { super(cmp); } protected void applySortMethod(List<E> list) { Collections.sort(list, getComparator()); } }
/* final class MergeSorter<E extends Comparable<E>> extends AbstractExchangeSorterAnalyzer<E> { private List<E> valuesToSort; private List<E> mergedValues; public MergeSorter() { super(); } public MergeSorter(Comparator<E> cmp) { super(cmp); } private void createMergedValues(int n) { mergedValues = new ArrayList<E>(n); while (n-- > 0) mergedValues.add(null); } private void merge(int iStart, int iEnd, int jStart, int jEnd) { E nextValue; int i = iStart, j = jStart; int k = i; // TO DO: FINISHwhile (i <= iEnd && j <= jEnd) { final E iValue = valuesToSort.get(i); final E jValue = valuesToSort.get(j); if (compare(iValue, jValue) < 0) { nextValue = iValue; i++; } else { nextValue = jValue; j++; } mergedValues.set(k++, nextValue); } while (i <= iEnd) { nextValue = valuesToSort.get(i++); mergedValues.set(k++, nextValue); } while (j <= jEnd) { nextValue = valuesToSort.get(j++); mergedValues.set(k++, nextValue); }}
private void mergeSort(int i, int j) { final int n = (j - i) + 1; if (n < 2) return; int startRight = i + (n / 2); int endLeft = startRight - 1; // TO DO: FINISHif (n > 1) { mergeSort(i, endLeft); mergeSort(startRight, j); } merge(i, endLeft, startRight, j); for (int k = i; k <= j; k++) valuesToSort.set(k, mergedValues.get(k));} protected void applySortMethod(List<E> list) { final int n = list.size(); if (n < 2) return; valuesToSort = list; createMergedValues(n); mergeSort(0, n - 1); } } */
/******************/ /* SORTER FACTORY */ /******************/ final class SorterFactory<E extends Comparable<E>> { public List<ExchangeSorterAnalyzer<E>> makeExchangeSorters() { List<ExchangeSorterAnalyzer<E>> sorters; sorters = new LinkedList<ExchangeSorterAnalyzer<E>>(); sorters.add(new BubbleSorter<E>()); sorters.add(new SelectionSorter<E>()); sorters.add(new InsertionSorter<E>()); sorters.add(new QuickSorter<E>()); sorters.add(new CollectionsSorter<E>()); //sorters.add(new MergeSorter<E>()); return sorters; } } /**********/ /* COPIER */ /**********/ final class Copier { public static <E> List<E> copy(Iterable<E> list) { List<E> copyOfList = new LinkedList<E>(); for (E element : list) copyOfList.add(element); return copyOfList; } } /*************/ /* SHUFFLERS */ /*************/ final class KnuthShuffler<E> implements Shuffler<E> { private int getRandomIntegerBetween(int lower, int upper) { final int diff = upper - lower; return lower + (int)(Math.random() * (diff + 1)); } public List<E> shuffle(List<E> list) { final int lastIndex = list.size() - 1; for (int i = 0; i < lastIndex; i++) { int j = getRandomIntegerBetween(i, lastIndex); E tmp = list.get(i); list.set(i, list.get(j)); list.set(j, tmp); } return list; } } final class SortShuffler<E> implements Shuffler<E> { public List<E> shuffle(List<E> list) { Collections.sort(list, (E l, E r) -> (int)(Math.random() - 0.5)); return list; } }
/* A permutation of a finite set is an arrangement of its elements into a row. * * — DONALD E. KNUTH, The Art of Computer Programming, vol. 3 (1998) */ /************/ /* PERMUTER */ /************/ final class RecursivePermuter<E> implements Permuter<E> { public final List<List<E>> allPermutationsOf(List<E> list) { return allPermutationsOf(list, 0); } private List<List<E>> allPermutationsOf(List<E> list, int headIndex) { final int permutationLength = list.size() - headIndex; List<List<E>> allPermutations = new ArrayList<List<E>>(); if (permutationLength > 0) { E theHeadElement = list.get(headIndex); List<List<E>> allPermutationsOfTail = allPermutationsOf(list, headIndex + 1); for (List<E> permutationOfTail : allPermutationsOfTail) { final int lastIndex = permutationLength - 1; for (int putHeadAtIndex = 0; putHeadAtIndex <= lastIndex; putHeadAtIndex++) { List<E> newPermutation = new ArrayList<E>(permutationLength); for (int i = 0; i < lastIndex; i++) { E nextTailElement = permutationOfTail.get(i); if (putHeadAtIndex == i) { newPermutation.add(theHeadElement); } newPermutation.add(nextTailElement); } if (putHeadAtIndex == lastIndex) { newPermutation.add(theHeadElement); } allPermutations.add(newPermutation); } } } else { allPermutations.add(new ArrayList<E>()); // There is one way to arrange no elements. } return allPermutations; } }
/********************/ /* ANALYSIS PRINTER */ /********************/ final class AnalysisPrinter<E extends Comparable<E>> { private final String TAB = "\t", NEW_LINE = "\n"; public final void printHeaderRow() { // OOPS! These headings are out of order!! final String headings[] = { "row_size", "times_sorted", "min_cmp", "max_cmp", "avg_cmp", "sd_cmp", "min_xch", "max_xch", "avg_xch", "sd_xch", "min_nano_sec", "max_nano_sec", "avg_nano_sec", "sd_nano_sec" }; final StringBuilder sb = new StringBuilder("sorter"); for (String heading : headings) sb.append( TAB + heading); System.out.print(sb + NEW_LINE); } private final void printMetrics(IntegralMetrics metrics) { System.out.print(TAB + metrics.min()); System.out.print(TAB + metrics.max()); System.out.print(TAB + metrics.avg()); System.out.print(TAB + metrics.sd()); } private final void printAnalysis(ComparisonAlgorithmAnalysis analysis) { printMetrics(analysis.elapsedTime()); printMetrics(analysis.comparisons()); } private final void printAnalysis(ExchangeSortingAnalysis analysis) { printMetrics(analysis.elapsedTime()); printMetrics(analysis.comparisons()); printMetrics(analysis.exchanges()); } public final void printDataRow(SearcherAnalyzer<E> searcher, int n) { System.out.print(searcher + TAB + n + TAB + searcher.getCount()); printAnalysis(searcher); System.out.println(); } public final void printDataRow(SorterAnalyzer<E> sorter, int n) { System.out.print(sorter + TAB + n + TAB + sorter.getCount()); printAnalysis(sorter); System.out.println(); } public final void printDataRow(ExchangeSorterAnalyzer<E> sorter, int n) { System.out.print(sorter + TAB + n + TAB + sorter.getCount()); printAnalysis(sorter); System.out.println(); } }
/* The time required to sort N records, using a decent general-purpose sorting algorithm, * is roughly proportional to N log N; we make about log N “passes” over the data. This is * the minimal time, as we shall see in Section 5.3.1 if the records are in random order * and if sorting is done by pairwise comparisons of keys. * * — DONALD E. KNUTH, The Art of Computer Programming, vol. 3 (1998) */ /********************/ /* SORTING ANALYZER */ /********************/ final class SortingAnalyzer<E extends Comparable<E>> { private final int rowSizeTippingPoint, sampleSize; private final Permuter<E> permuter = new RecursivePermuter<E>(); private final SorterFactory<E> sorterFactory = new SorterFactory<E>(); private final Shuffler<E> shuffler = new KnuthShuffler<E>(); private final AnalysisPrinter<E> printer = new AnalysisPrinter<E>(); private List<ExchangeSorterAnalyzer<E>> sorters; private boolean headerPrinted = false; public SortingAnalyzer(int rowSizeTippingPoint, int sampleSize) { this.rowSizeTippingPoint = rowSizeTippingPoint; this.sampleSize = sampleSize; } private void sortCopiesOf(List<E> permutation) { for (Sorter<E> sorter : sorters) sorter.sort(Copier.copy(permutation)); } private final void sortAllPermutationsOf(List<E> row) { for (List<E> permutation : permuter.allPermutationsOf(row)) sortCopiesOf(permutation); } private final void sortShufflingsOf(List<E> row, int timesToSort) { final List<E> list = Copier.copy(row); while (timesToSort-- > 0) sortCopiesOf(shuffler.shuffle(list)); } public final void sortPermutationsOf(List<E> row) { sorters = sorterFactory.makeExchangeSorters(); final int rowSize = row.size(); if (rowSize < rowSizeTippingPoint) sortAllPermutationsOf(row); else sortShufflingsOf(row, sampleSize); if (!headerPrinted) { printer.printHeaderRow(); headerPrinted = true; } for (ExchangeSorterAnalyzer<E> sorter : sorters) printer.printDataRow(sorter, rowSize); } }
/* The character is believed to have initiated a phenomenon referred to as * “The Scully Effect”; as the medical doctor and the FBI Special Agent inspired * many young women to pursue careers in science, medicine and law enforcement, * and as a result brought a perceptible increase in the number of women * in those fields. * * https://en.wikipedia.org/wiki/Dana_Scully (accessed on 30 April 2018) */ /**************************/ /* SORTING ANALYZER AGENT */ /**************************/ final class SortingAnalyzerAgent { private final SortingAnalyzer<String> analyzer; public SortingAnalyzerAgent(int rowSizeTippingPoint, int sampleSize) { analyzer = new SortingAnalyzer<String>(rowSizeTippingPoint, sampleSize); } private List<List<String>> makeRowsToSort(String[] args) { final List<List<String>> rows = new LinkedList<List<String>>(); final int n = args.length; for (int i = 1; i < n; i++) { final List<String> row = new LinkedList<String>(); final int rowSize = Integer.parseInt(args[i]); for (Integer element = 1; element <= rowSize; element++) row.add(element.toString()); rows.add(row); } return rows; } private List<String> makeRowToSort(String[] args) { final List<String> row = new LinkedList<String>(); final int n = args.length; for (int i = 1; i < n; i++) row.add(args[i]); return row; } public final void analyzeSortingAlgorithms(String[] args, String arg0) { if (arg0.equals("sort_rows_of_size")) { System.out.println("Sorting permutations of zero or many rows...\n"); for (List<String> row : makeRowsToSort(args)) analyzer.sortPermutationsOf(row); } else if (arg0.equals("sort")) { System.out.println("Sorting permutations of a single row...\n"); analyzer.sortPermutationsOf(makeRowToSort(args)); } } }
/* Ada Lovelace was the first person to publish an algorithm intended to be executed * by the first modern computer, the Analytical Engine created by Charles Babbage. * Because of this, she is often regarded as the first computer programmer, ... * * https://en.wikipedia.org/wiki/Women_in_computing (accessed on 30 April 2018) */ /***************/ /* MAIN METHOD */ /***************/ final public class AnalysisOfAlgorithms { private static final int ROW_SIZE_TIPPING_POINT = 8; private static final int SAMPLE_SIZE = 1000; private static void println(String s) { System.out.println(s); } public static void main(String[] args) { final String arg0 = args.length > 0 ? args[0] : ""; final String arg2 = args.length > 2 ? args[2] : ""; if (arg0.equals("search_for") && (arg2.equals("in") || arg2.equals("in_rows_of_size"))) { System.out.println("Sorry. Searching is not implemented yet."); } else if (arg0.equals("sort") || arg0.equals("sort_rows_of_size")) { final SortingAnalyzerAgent agentLovelace = new SortingAnalyzerAgent( ROW_SIZE_TIPPING_POINT, SAMPLE_SIZE); agentLovelace.analyzeSortingAlgorithms(args, arg0); } else { println("This program is designed to sort or search permutations of values and output an"); println("analysis of the sorting or searching algorithms used. When fully implemented,"); println("the program will respond to command-line arguments as follows.\n"); println("1. If the first command-line argument is sort or sort_rows_of_size, then"); println(" the program will attempt to sort several permutations of rows of values.\n"); println(" a) If the first argument is sort_rows_of_size, then the remaining arguments"); println(" should be non-negative integers specifying the sizes of rows of strings"); println(" to be generated, permuted, and sorted."); println(" b) Otherwise, the remaining arguments will be the elements of a row of strings"); println(" to be permuted and sorted.\n"); println("2. If the first command-line argument is search_for and the third argument"); println(" is in or in_rows_of_size, then the program will attempt to search for"); println(" the string passed as the second argument.\n"); println(" a) If the third argument is in_rows_of_size, then the remaining arguments"); println(" should be non-negative integers specifying the sizes of rows of strings"); println(" to be generated, permuted, and searched."); println(" b) Otherwise, the remaining arguments will be the elements of a row of strings"); println(" to be permuted and searched.\n"); println("3. Otherwise, this documentation is printed.\n"); println("An exception will be thrown if an argument that should represent a row size is not"); println("an integer or if the integral value is too large or too small.\n"); println("This version is not fully implemented. It doesn't support searching yet."); } } }
/*********************************************************************************************************/ /* A SHORT ROW TO HOE: a title devised to avoid the word EXERCISES, which many students find frightening */ /*********************************************************************************************************/ /* 0. Use this program to sort the row: 503 087 512 061 908 170 897 275 653 426 154 509 612 677 765 703 * Use it to sort permutations of rows of size: 0 1 2 3 4 ... * Use it to sort permutations of rows of size: 1 2 4 8 16 ... * * Copy the program’s output and paste it into a spreadsheet application like Excel or Libre Office * Calc. Use pivot tables and charts to study how execution time, comparison counts, and exchange * counts vary across different sorting algorithms and row sizes. What did you learn? Did anything * surprise you? Were any unanswered questions raised? If so, which question is most interesting to * you, and how might you go about trying to find an answer? Where did those random numbers come from? * * 1. What is the largest row size you can sort permutations of using the program as it is written? How can * you change the program to sort permutations of larger rows? What is the largest row size you can sort * permutations of if you are only allowed to modify the AnalysisOfAlgorithms class? What did you change? * * 2. Using a slightly modified version of this program (you may modify the AnalysisOfAlgorithms class), * what is the maximum number of times per sorting algorithm that you can sort the sixteen three-digit * numbers shown above in exercise 1? What limits you? Your own patience? Some other finite resource? * * 3. How do the sorting algorithms implemented by the program compare in terms of execution time, * comparison counts, and exchange counts? Which algorithm is best? Which algorithm is worst? Which * algorithm is the most predictable? Which is the least predictable? What assumptions are you making? * * 4. How does the best algorithm compare to the second best algorithm? Define best. Can you make any * improvements to either one? Can you implement an algorithm that is better than the best one? Are * you encouraged or discouraged by what you’ve discovered? Are you motivated? In what sense? * * 5. Run this program on different computers. Try using different online Java IDEs. What can you learn * about the capabilities of different platforms using this program? What did you learn? * * 6. Enhance this program so that it can be used, per the program’s documentation, to analyze searching * algorithms in addition to sorting algorithms. Use the search-related interfaces provided, and * extend the AbstractComparisonAlgorithmAnalyzer class. (Use the AbstractSorterAnalyzer class as * an example.) Implement binary and linear search algorithms, and use the enhanced program to * analyze your algorithms. What is an elephant in Cairo, and why is this question relevant? * * 7. List the basic features and capabilities of the Java programming language used by this program. * What basic features are not used? What advanced features does this program use? Explain * what the following terms mean and provide examples from this program of each: interface, class * constructor, local variable, constant variable, instance variable, class variable, parameter * argument, lambda expression, inheritance, subtyping, subclassing, polymorphism, method overriding, * method overloading, lambda expression, generics, recursion. Cite your sources. * * 8. On page 453, the authors of Introduction to Computer Science: An Interdisiplinary Approach (2017) * say that subclassing is controversial because its advantages over subtyping are debatable. What are * some advantages and disadvantages of subclassing? Is the use of subclassing in this program safe? * Is it justified? Why? How can subclassing be used responsibly? How can it be prevented? Should * CounterMayThrowException be final? Which of the overloaded versions of Collections.sort exemplifies * dependency injection? How are dependency injection and subtyping related? Is dependency injection * dangerous? Is SortShuffler.shuffle using or being reckless with Collections.sort? * * 9. Is Java too full of rules and constraints? Do you value creativity over predictability? */