<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>乌鸦的仓库</title>
    <description></description>
    <link>http://ravenex.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
          <item>
        <title>几种排序算法的对比</title>
        <author>ravenex</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ravenex.javaeye.com">ravenex</a>&nbsp;
                    链接：<a href="http://ravenex.javaeye.com/blog/175557" style="color:red;">http://ravenex.javaeye.com/blog/175557</a>&nbsp;
          发表时间: 2008年03月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="quote_title">引用</div><div class="quote_div"><strong>Programming: Sort Testing</strong><br /><br />Your task this week is to implement four sorts, and do experiments to see how fast they run for different sizes and types of input data sets. The sorts are: selection sort, insertion sort, bubble sort and merge sort.<br /><br />We're interested in two "modes" for your program:<br /><br />A <strong>demonstration mode</strong> takes in a data set from the user, sorts it with each sorting algorithm, and prints out the data set at each step during each sort. In particular, it prints the entire set after each selection, each insertion, and each bubble swap. For merge sort, it describes each split into smaller subsets, and each merge into a unified subset. (Your output should match example output below.) <br />A <strong>comparison mode</strong> does not take a data set from the user or print out any data sets. Rather, it takes a single integer from the user, which is a set size. The program then constructs four data sets of that size: an already sorted set, a reverse-sorted set, a random set, and an "almost-sorted set" where approximately 20% of the elements are out of sort order. The program then uses all four sorts (insertion, selection, bubble, merge) to sort each of the four sets, and times how long each sort took to complete. The program then repeats the entire process for ten trials, and finds an average time for each sort, for each set type. Each of these averages (16 in all, from 160 trials) is then printed out for the user. <br />The usage of the program is:<br /><br />$ java SortTester [1 or more integers]<br /><br />If one integer is given, the program goes into comparison mode for input sets of the given size. If more than one integer is given, the program goes into demonstration mode and sorts the given set of integers.<br /><br />You do not have to implement the user interface or even the code that collects and reports running-time data. That is all provided. Your only job is to fill in the actual routines that run the four sorts. However, please look over the provided code carefully so that you understand what it is doing, and why.<br /><br /><br />Please work from the following files:<br /><br />SortTester.java is the driver class. It accepts and parses integer input from the user, and contains code to perform both demonstration and comparison modes. In the case of comparison mode, it generates sample sets, runs the sorts, and reports the average running times. You do not need to modify this file. <br />Sorters.java is the back-end that contains functions for performing the four sorts. There is one function set up for you for each sort. The functions take the form of<br /><pre name="code" class="java">public static double sortType (int[] set, boolean printSteps)</pre><br />The first argument, set, is the set of integers you are to sort. The second argument, printSteps, is true if the driver wants step-by-step printouts of how the function is sorting the array (i.e., demonstration mode), and false if the driver wants no printed output whatsoever (i.e., comparison mode). It is critical that if printSteps is false, no output is printed. This is because the act of printing is very, very slow, enough to dwarf the time it actually takes to sort. You will end up timing how long it takes to print, rather than how long it takes to sort.<br /><br />The function returns a double of the number of milliseconds it takes to perform the sort. You do not need to figure out how to calculate the running time of the function; that is already provided in the framework. At the beginning of the function, the current system time is recorded. At the end of the function, the current system time is recorded again, and the difference between those two times is returned. Do not alter these lines, or else you may return erroneous running time results. <br /><br /><br />Once you have completed the code, perform experiments to see how long the four sorts take on different sizes and styles of input. Specifically, run your program in comparison mode for sets of 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000 and 10000. Plot the results on four graphs, one for each set type. Each set type graph should contain four plots, one for each sort type. The x axis of all four graphs should be the set size, from 1000 to 10000. The y axis should be the running time in milliseconds reported by your program, from 0 to the maximum time encountered in your experiment. (All four graphs should be scaled the same on both axes.) <br /><br />You may use Microsoft Excel or any other plotting program to do your graphs. Feel free to modify the formatting of the output (in SortTester.java) so that it can be easily copied into Excel -- 160 numbers is a lot to copy by hand. If you like, you can try gnuplot, a free graphing program installed on Cunix. The usage would be<br /><br />$ gnuplot HW3Sorted.gp<br /><br />where HW3Sorted.gp is an input file that contains instructions about how to set up the graph, as well as the actual data to plot. The output is stored in a postscript file HW3Sorted.ps. Here is a sample gnuplot file that you can modify to fit your needs. (The output file name, and file format, are set as options in that file.)<br /><br />Include your graphs, in PS (postscript), TIF or PDF files, as well as the output data from which you constructed your graphs, with your submission. Name the graphs and output file(s) so it is clear which is which. Do not submit graphs in any other format.<br /><br />Example Output<br /><pre name="code" class="java">$ java SortTester 9 5 1 7 9 20 2 5 6
SELECTION SORT 
9 5 1 7 9 20 2 5 6 
1 5 9 7 9 20 2 5 6 
1 2 9 7 9 20 5 5 6 
1 2 5 7 9 20 5 9 6 
1 2 5 5 9 20 7 9 6 
1 2 5 5 6 20 7 9 9 
1 2 5 5 6 7 20 9 9 
1 2 5 5 6 7 9 9 20 
1 2 5 5 6 7 9 9 20 
-=-=-=-=-=-=-=- 
INSERTION 
9 5 1 7 9 20 2 5 6 
5 9 1 7 9 20 2 5 6 
1 5 9 7 9 20 2 5 6 
1 5 7 9 9 20 2 5 6 
1 5 7 9 9 20 2 5 6 
1 5 7 9 9 20 2 5 6 
1 2 5 7 9 9 20 5 6 
1 2 5 5 7 9 9 20 6 
1 2 5 5 6 7 9 9 20 
-=-=-=-=-=-=-=- 
BUBBLE 
9 5 1 7 9 20 2 5 6 
Round 1 
5 9 1 7 9 20 2 5 6 
5 1 9 7 9 20 2 5 6 
5 1 7 9 9 20 2 5 6 
5 1 7 9 9 2 20 5 6 
5 1 7 9 9 2 5 20 6 
5 1 7 9 9 2 5 6 20 
Round 2 
1 5 7 9 9 2 5 6 20 
1 5 7 9 2 9 5 6 20 
1 5 7 9 2 5 9 6 20 
1 5 7 9 2 5 6 9 20 
Round 3 
1 5 7 2 9 5 6 9 20 
1 5 7 2 5 9 6 9 20 
1 5 7 2 5 6 9 9 20 
Round 4 
1 5 2 7 5 6 9 9 20 
1 5 2 5 7 6 9 9 20 
1 5 2 5 6 7 9 9 20 
Round 5 
1 2 5 5 6 7 9 9 20 
Round 6 
No swaps. Final set: 
1 2 5 5 6 7 9 9 20 
-=-=-=-=-=-=-=- 
MERGE 
9 5 1 7 9 20 2 5 6 
Divided 9 5 1 7 9 20 2 5 6 into 9 5 1 7 and 9 20 2 5 6 
Divided 9 5 1 7 into 9 5 and 1 7 
Divided 9 5 into 9 and 5 
Merged 9 and 5 into 5 9 
Divided 1 7 into 1 and 7 
Merged 1 and 7 into 1 7 
Merged 5 9 and 1 7 into 1 5 7 9 
Divided 9 20 2 5 6 into 9 20 and 2 5 6 
Divided 9 20 into 9 and 20 
Merged 9 and 20 into 9 20 
Divided 2 5 6 into 2 and 5 6 
Divided 5 6 into 5 and 6 
Merged 5 and 6 into 5 6 
Merged 2 and 5 6 into 2 5 6 
Merged 9 20 and 2 5 6 into 2 5 6 9 20 
Merged 1 5 7 9 and 2 5 6 9 20 into 1 2 5 5 6 7 9 9 20 
1 2 5 5 6 7 9 9 20</pre><br /><br /><pre name="code" class="java">$ java SortTester 10000 
Testing performance for sets of 10000, 10 trials... 
SELECTION SORTED 10000 130.6 
SELECTION ALMOST-SORTED 10000 130.4 
SELECTION REVERSE 10000 131.0 
SELECTION RANDOM 10000 131.0 
INSERTION SORTED 10000 0.2 
INSERTION ALMOST-SORTED 10000 25.6 
INSERTION REVERSE 10000 218.2 
INSERTION RANDOM 10000 109.5 
BUBBLE SORTED 10000 0.0 
BUBBLE ALMOST-SORTED 10000 523.9 
BUBBLE REVERSE 10000 676.1 
BUBBLE RANDOM 10000 689.3 
MERGE SORTED 10000 5.3 
MERGE ALMOST-SORTED 10000 4.2 
MERGE REVERSE 10000 3.9 
MERGE RANDOM 10000 5.2</pre><br /><br /><br /><strong>Programming Analysis</strong><br /><br />Answer the following questions in your README (each worth 5 points):<br /><br /><br />For already sorted input, why did the running time for each sort grow as it did with respect to set size? Which sort(s) were able to efficiently recognize already-sorted input, and which continued to take quadratic time as sets grew larger? Why?<br /><br />What was the ranking of your sorts from fastest to slowest for random input? Why did the slowest sorts perform slowest, and the fastest ones perform fastest? Did your results here match up with expectations? <br /><br />What differences, if any, do you see between the performances of your sorts over reverse-sorted input and random input? How do you explain these differences or lack of differences?<br /><br />What differences, if any, do you notice between random input and almost-sorted input? (One of your sorts should have performed surprisingly differently, where the other three performed more or less the same.) How can you explain this? What can you conclude about the suitability of different sorts for different types of input data? <br /><br /><br /><strong>Extra Credit</strong><br /><br />10 points extra credit for including two variations of Shellsort (Shellsort-A and Shellsort-B) throughout the entire programming assignment (and analysis). This will require adjusting both Java files and adding new plots to all four graphs. Shellsort-A should start with an interval of 1/2 input size and reduce the interval by half on each iteration. (Recall that Shellsort reverts to insertion sort once the interval is 1, and while sorting every "slice" as we discussed in class.) Shellsort-B should start with an interval of 1/2 input size and each iteration should reduce the interval by 2/3 (e.g., 120 goes to 40). For demonstration mode, both should first print the gap sequence they will use, then, for each interval in the gap sequence, each slice, before and after sorting that slice, and then the complete list after the slices are reassembled. (You do not need to print the details of insertion sort for each individual slice). Be sure to test on lists with duplicate elements! (You can modify the driver code, SortTester, to create such lists to test on.) What differences do you see between the performance of Shellsort-A and Shellsort-B, if any? How do you explain these differences by the interval reduction strategy? Do you notice anything unusual if the input size is a power of 2? (Recall our discussion of Shell's gap sequence, which goes by powers of 2.)<br /><br />10 points extra credit for including four variations of quicksort (quicksort-A through quicksort-D) throughout the entire programming assignment (and analysis). This will require adjusting both Java files and adding new plots to all four graphs. Quicksort-A should use the middle element as the pivot; quicksort-B should use median-of-three pivot selection; quicksort-C should use median-of-five, and quicksort-D should (update) use the actual median element (i.e., scan the entire list and calculate the optimal pivot). For demonstration mode, each recursive call to quicksort should print the original list, the pivot selected, each pair of elements that are swapped, and the final list, with a clear distinction between left partition, pivot and right partition. Be sure to test on lists with duplicate elements! (You can modify the driver code, SortTester, to create such lists to test on.) How does quicksort match up against the other sorts, mergesort in particular? For each type of input set, how did pivot selection affect quicksort running time? How do you explain these differences? <em>(Note: quicksort-A may crash on Cunix for large data sets due to running out of memory. Don't panic if this happens. Document the set size where quicksort runs out of memeory, and include quicksort-A on your graph only up until that set size.)</em></div><br /><br />SortTester.java:<br /><pre name="code" class="java">import java.util.Random;

/**
 * Sort-tester driver class for 3134 S08 HW3. DKE, 2/2008
 */
public class SortTester {

    /**
     * Constructor receives command-line arguments.
     */
    public SortTester(String[] args) throws Exception {

        // At least one argument required.
        if (args.length &lt; 1) {
            throw new Exception(
                    "SortTester must be run with at least 1 integer argument.");
        }

        if (args.length == 1) {

            // If the user gave one argument it is assumed to be a set
            // size for comparison mode.
            comparison(Integer.parseInt(args[0]));
        } else {

            // Otherwise, the multiple arguments are assumed to be
            // a set for demonstration mode.
            demonstration(args);
        }

    }

    /**
     * Main function constructs a SortTester object.
     */
    public static void main(String[] args) throws Exception {
        try {
            new SortTester(args);
        } catch (Exception e) {
            //System.err.println(e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * Sort the set provided the user. Demonstrate how the various sets work.
     */
    public void demonstration(String[] stringSet) throws Exception {

        int[] set;

        /**
         * Prepare an array of ints that is the same size as the array of
         * strings given at the command line.
         */
        set = new int[stringSet.length];

        // Convert the strings to ints..
        // For each string in the input set...
        for (int i = 0; i &lt; stringSet.length; i++) {

            String token = stringSet[i];

            try {
                // Convert the string to int.
                set[i] = Integer.parseInt(token);
            } catch (NumberFormatException e) {
                throw new Exception("Bad integer in position " + (i + 1) + ": "
                        + token);
            }
        }

        System.out.println("Ready to sort " + set.length + " integers.");

        // Run selection sort
        Sorters.selectionSort(makeCopy(set), true);

        // Run insertion sort
        Sorters.insertionSort(makeCopy(set), true);

        // Run bubble sort
        Sorters.bubbleSort(makeCopy(set), true);

        // Run merge sort
        Sorters.mergeSort(makeCopy(set), true);

        // Run Shellsort-A
        Sorters.shellSortA(makeCopy(set), true);
        
        // Run Shellsort-B
        Sorters.shellSortB(makeCopy(set), true);
        
        // Run Quicksort-A
        Sorters.quickSortA(makeCopy(set), true);
        
        // Run Quicksort-B
        Sorters.quickSortB(makeCopy(set), true);
        
        // Run Quicksort-C
        Sorters.quickSortC(makeCopy(set), true);
        
        // Run Quicksort-D
        Sorters.quickSortD(makeCopy(set), true);
    }

    public static int[] makeCopy(int[] set) {

        int[] result = new int[set.length];
        for (int i = 0; i &lt; set.length; i++) {
            result[i] = set[i];
        }
        return result;
    }

    /**
     * Run each the sorts 10 times on a user-given set size and report the
     * average time it took for each sort to run.
     */
    public void comparison(int setSize) throws Exception {

        // Number of trials
        int trials = 10;
        // Matrix stores the times for each experiment
        // First [] stores the sort type, from 0 to 9
        // Second [] stores the set type, from 0 to 3
        double[][] times = new double[10][4];

        int[] set;

        System.out.println("Testing performance for sets of " + setSize + ", "
                + trials + " trials...");

        // For each trial...
        for (int i = 0; i &lt; trials; i++) {

            // Make a sorted set and do selection sort
            set = makeSortedSet(setSize);
            times[0][0] += Sorters.selectionSort(set, false);

            // Make a sorted set and do insertion sort
            set = makeSortedSet(setSize);
            times[1][0] += Sorters.insertionSort(set, false);

            // Make a sorted set and do bubble sort
            set = makeSortedSet(setSize);
            times[2][0] += Sorters.bubbleSort(set, false);

            // Make an sorted set and do merge sort
            set = makeSortedSet(setSize);
            times[3][0] += Sorters.mergeSort(set, false);
            
            // Make an sorted set and do Shellsort-A
            set = makeSortedSet(setSize);
            times[4][0] += Sorters.shellSortA(set, false);
            
            // Make an sorted set and do Shellsort-B
            set = makeSortedSet(setSize);
            times[5][0] += Sorters.shellSortB(set, false);
            
            // Make an sorted set and do Quicksort-A
            set = makeSortedSet(setSize);
            times[6][0] += Sorters.quickSortA(set, false);
            
            // Make an sorted set and do Quicksort-B
            set = makeSortedSet(setSize);
            times[7][0] += Sorters.quickSortB(set, false);
            
            // Make an sorted set and do Quicksort-C
            set = makeSortedSet(setSize);
            times[8][0] += Sorters.quickSortC(set, false);
            
            // Make an sorted set and do Quicksort-D
            set = makeSortedSet(setSize);
            times[9][0] += Sorters.quickSortD(set, false);

            // Make an almost sorted set and do selection sort
            set = makeAlmostSortedSet(setSize);
            times[0][1] += Sorters.selectionSort(set, false);

            // Make an almost sorted set and do insertion sort
            set = makeAlmostSortedSet(setSize);
            times[1][1] += Sorters.insertionSort(set, false);

            // Make an almost sorted set and do bubble sort
            set = makeAlmostSortedSet(setSize);
            times[2][1] += Sorters.bubbleSort(set, false);

            // Make an almost sorted set and do merge sort
            set = makeAlmostSortedSet(setSize);
            times[3][1] += Sorters.mergeSort(set, false);
            
            // Make an almost sorted set and do Shellsort-A
            set = makeAlmostSortedSet(setSize);
            times[4][1] += Sorters.shellSortA(set, false);
            
            // Make an almost sorted set and do Shellsort-B
            set = makeAlmostSortedSet(setSize);
            times[5][1] += Sorters.shellSortB(set, false);
            
            // Make an almost sorted set and do Quicksort-A
            set = makeAlmostSortedSet(setSize);
            times[6][1] += Sorters.quickSortA(set, false);
            
            // Make an almost sorted set and do Quicksort-B
            set = makeAlmostSortedSet(setSize);
            times[7][1] += Sorters.quickSortB(set, false);
            
            // Make an almost sorted set and do Quicksort-C
            set = makeAlmostSortedSet(setSize);
            times[8][1] += Sorters.quickSortC(set, false);
            
            // Make an almost sorted set and do Quicksort-D
            set = makeAlmostSortedSet(setSize);
            times[9][1] += Sorters.quickSortD(set, false);

            // Make a reverse sorted set and do selection sort
            set = makeReverseSet(setSize);
            times[0][2] += Sorters.selectionSort(set, false);

            // Make a reverse sorted set and do insertion sort
            set = makeReverseSet(setSize);
            times[1][2] += Sorters.insertionSort(set, false);

            // Make a reverse sorted set and do bubble sort
            set = makeReverseSet(setSize);
            times[2][2] += Sorters.bubbleSort(set, false);

            // Make a reverse sorted set and do merge sort
            set = makeReverseSet(setSize);
            times[3][2] += Sorters.mergeSort(set, false);
            
            // Make an reverse sorted set and do Shellsort-A
            set = makeReverseSet(setSize);
            times[4][2] += Sorters.shellSortA(set, false);
            
            // Make an reverse sorted set and do Shellsort-B
            set = makeReverseSet(setSize);
            times[5][2] += Sorters.shellSortB(set, false);
            
            // Make an reverse sorted set and do Quicksort-A
            set = makeReverseSet(setSize);
            times[6][2] += Sorters.quickSortA(set, false);
            
            // Make an reverse sorted set and do Quicksort-B
            set = makeReverseSet(setSize);
            times[7][2] += Sorters.quickSortB(set, false);
            
            // Make an reverse sorted set and do Quicksort-C
            set = makeReverseSet(setSize);
            times[8][2] += Sorters.quickSortC(set, false);
            
            // Make an reverse sorted set and do Quicksort-D
            set = makeReverseSet(setSize);
            times[9][2] += Sorters.quickSortD(set, false);

            // Make a random set and do selection sort
            set = makeRandomSet(setSize);
            times[0][3] += Sorters.selectionSort(set, false);

            // Make a random set and do insertion sort
            set = makeRandomSet(setSize);
            times[1][3] += Sorters.insertionSort(set, false);

            // Make a random set and do bubble sort
            set = makeRandomSet(setSize);
            times[2][3] += Sorters.bubbleSort(set, false);

            // Make a random set and do merge sort
            set = makeRandomSet(setSize);
            times[3][3] += Sorters.mergeSort(set, false);
            
            // Make an random set and do Shellsort-A
            set = makeRandomSet(setSize);
            times[4][3] += Sorters.shellSortA(set, false);
            
            // Make an random set and do Shellsort-B
            set = makeRandomSet(setSize);
            times[5][3] += Sorters.shellSortB(set, false);
            
            // Make an random set and do Quicksort-A
            set = makeRandomSet(setSize);
            times[6][3] += Sorters.quickSortA(set, false);
            
            // Make an random set and do Quicksort-B
            set = makeRandomSet(setSize);
            times[7][3] += Sorters.quickSortB(set, false);
            
            // Make an random set and do Quicksort-C
            set = makeRandomSet(setSize);
            times[8][3] += Sorters.quickSortC(set, false);
            
            // Make an random set and do Quicksort-D
            set = makeRandomSet(setSize);
            times[9][3] += Sorters.quickSortD(set, false);
        }

        // Now we need to compile and print the results.
        // For each sort type...
        for (int sortType = 0; sortType &lt; 10; sortType++) {

            // Choose the string that represents the sort type
            String sortTypeString;
            if (sortType == 0) {
                sortTypeString = "SELECTION";
            } else if (sortType == 1) {
                sortTypeString = "INSERTION";
            } else if (sortType == 2) {
                sortTypeString = "BUBBLE";
            } else if (sortType == 3) {
                sortTypeString = "MERGE";
            } else if (sortType == 4) {
                sortTypeString = "SHELLSORT-A";
            } else if (sortType == 5) {
                sortTypeString = "SHELLSORT-B";
            } else if (sortType == 6) {
                sortTypeString = "QUICKSORT-A";
            } else if (sortType == 7) {
                sortTypeString = "QUICKSORT-B";
            } else if (sortType ==<img src="/images/smiles/icon_cool.gif"/>{
                sortTypeString = "QUICKSORT-C";
            } else {
                sortTypeString = "QUICKSORT-D";
            }

            // For each set type..
            for (int setType = 0; setType &lt; 4; setType++) {

                // Find the AVERAGE time among the trials by dividing the
                // running sum by the number of trials
                times[sortType][setType] /= trials;

                // Choose the string that represents the set type
                String setTypeString;
                if (setType == 0) {
                    setTypeString = "SORTED";
                } else if (setType == 1) {
                    setTypeString = "ALMOST-SORTED";
                } else if (setType == 2) {
                    setTypeString = "REVERSE";
                } else {
                    setTypeString = "RANDOM";
                }

                // Print the results
                System.out.println(sortTypeString + " " + setTypeString + " "
                        + setSize + " " + times[sortType][setType]);

            }
        }

    }

    /**
     * Make a sorted set of integers.
     */
    public static int[] makeSortedSet(int size) {

        int[] result = new int[size];

        for (int i = 0; i &lt; size; i++) {
            result[i] = i + 1;
        }

        return result;
    }

    /**
     * Make an almost-sorted set of integers.
     */
    public static int[] makeAlmostSortedSet(int size) {

        int[] result = new int[size];

        for (int i = 0; i &lt; size; i++) {
            result[i] = i + 1;
        }

        Random r = new Random();

        // Swap one-fifth of the elements with other elements
        for (int i = 0; i &lt; (size / 10); i++) {

            // Pick two random elements and swap them
            int firstToSwap = r.nextInt(size);
            int secondToSwap = r.nextInt(size);

            int crossover = result[firstToSwap];
            result[firstToSwap] = result[secondToSwap];
            result[secondToSwap] = crossover;
        }

        return result;
    }

    /**
     * Make a reverse-sorted set of integers.
     */
    public static int[] makeReverseSet(int size) {

        int[] result = new int[size];

        for (int i = 0; i &lt; size; i++) {
            result[i] = size - i;
        }

        return result;
    }

    /**
     * Make a random set of integers.
     */
    public static int[] makeRandomSet(int size) {

        Random r = new Random();

        int[] result = new int[size];

        for (int i = 0; i &lt; size; i++) {
            result[i] = r.nextInt();
        }

        return result;
    }
}</pre><br /><br />Sorters.java:<br /><pre name="code" class="java">/**
 * Back-end class for 3134 HW3. This is the one you edit.
 */
public class Sorters {

    /**
     * Run selection sort on a set.
     */
    public static double selectionSort(int[] set, boolean printSteps) {

        // Mark the start time.
        double startTime = System.currentTimeMillis();

        // Print the input set if we are asked to.
        if (printSteps) {
            System.out.println("SELECTION SORT");
            System.out.println(printList(set));
        }

        // DO SELECTION SORT HERE!
        // Print progress if printSteps is set to true.
        int length = set.length;
        for (int i = 0; i &lt; length - 1; ++i) {
            int minIdx = i;
            for (int j = i + 1; j &lt; length; ++j) {
                if (set[minIdx] > set[j]) {
                    minIdx = j;
                }
            }
            swap(set, i, set, minIdx);

            // print progress
            if (printSteps) {
                System.out.println(printList(set));
            }
        }

        // Print the output set if we are asked to.
        if (printSteps) {
            System.out.println("-=-=-=-=-=-=-=-");
        }

        // Mark the finish time and return the time it took to sort.
        return System.currentTimeMillis() - startTime;
    }

    /**
     * Run insertion sort on a set.
     */
    public static double insertionSort(int[] set, boolean printSteps) {

        // Mark the start time.
        double startTime = System.currentTimeMillis();

        insertionSort(set, 0, set.length - 1, printSteps);

        // Mark the finish time and return the time it took to sort.
        return System.currentTimeMillis() - startTime;
    }

    /**
     * Internal method shared by insertion sort and Quicksort methods.
     * 
     * @param set
     * @param left
     * @param right
     * @param printSteps
     */
    private static void insertionSort(int[] set, int left, int right,
            boolean printSteps) {

        int length = right - left + 1;

        // Print the input set if we are asked to.
        if (printSteps) {
            System.out.println("INSERTION");
            System.out.println(printList(set, left, length));
            ;
        }

        // DO INSERTION SORT HERE!
        // Print progress if printSteps is set to true.
        int j = 0;

        for (int i = left + 1; i &lt;= right; ++i) {
            // avoids explicit swap
            int min = set[i];
            for (j = i; (j > left) && (set[j - 1] > min); --j) {
                set[j] = set[j - 1];
            }
            set[j] = min;

            // print progress
            if (printSteps) {
                System.out.println(printList(set, left, length));
            }
        }

        // Print the output set if we are asked to.
        if (printSteps) {
            System.out.println("-=-=-=-=-=-=-=-");
        }
    }

    /**
     * Run bubble sort on a set.
     */
    public static double bubbleSort(int[] set, boolean printSteps) {

        // Mark the start time.
        double startTime = System.currentTimeMillis();

        // Print the input set if we are asked to.
        if (printSteps) {
            System.out.println("BUBBLE");
            System.out.println(printList(set));
        }

        // DO BUBBLE SORT HERE!
        // Print progress if printSteps is set to true.
        int length = set.length;
        for (int round = 1; round &lt; length; ++round) {
            boolean hasSwap = false;
            if (printSteps) {
                System.out.println("Round " + round);
            }
            for (int j = 0; j &lt; length - round; ++j) {
                if (set[j] > set[j + 1]) {
                    swap(set, j, set, j + 1);
                    hasSwap = true;
                    if (printSteps) {
                        System.out.println(printList(set));
                    }
                }
            }

            // the array is already sorted, end loop
            if (!hasSwap) {
                break;
            }
        }

        // Print the output set if we are asked to.
        if (printSteps) {
            System.out.println("No swaps.  Final set:");
            System.out.println(printList(set));
            ;
            System.out.println("-=-=-=-=-=-=-=-");
        }

        // Mark the finish time and return the time it took to sort.
        return System.currentTimeMillis() - startTime;

    }

    /**
     * Run merge sort on a set.
     */
    public static double mergeSort(int[] set, boolean printSteps) {

        // Mark the start time.
        double startTime = System.currentTimeMillis();

        // Print the input set if we are asked to.
        if (printSteps) {
            System.out.println("MERGE");
            System.out.println(printList(set));
        }

        // DO MERGE SORT HERE!
        // (You will need to call other functions, recursively)
        // Print progress if printSteps is set to true.
        int length = set.length;
        int[] copy = new int[length];
        mergeSort(set, copy, 0, length - 1, printSteps);

        // Print the output set if we are asked to.
        if (printSteps) {
            System.out.println(printList(set));
            System.out.println("-=-=-=-=-=-=-=-");
        }

        // Mark the finish time and return the time it took to sort.
        return System.currentTimeMillis() - startTime;
    }

    /**
     * Internal method that makes resursive calls.
     * 
     * @param array
     *            the original array to sort.
     * @param tempArray
     *            an array to place the merged result.
     * @param left
     *            the left-most index of the subarray.
     * @param right
     *            the right-most index of the subarray.
     * @param printSteps
     *            whether to print sort progress.
     */
    private static void mergeSort(int[] array, int[] tempArray, int left,
            int right, boolean printSteps) {
        if (left &lt; right) {
            int center = (left + right) / 2;
            if (printSteps) {
                System.out.print("Divided ");
                System.out.print(printList(array, left, right - left + 1));
                System.out.print(" into ");
                System.out.print(printList(array, left, center - left + 1));
                System.out.print(" and ");
                System.out
                        .println(printList(array, center + 1, right - center));
            }
            mergeSort(array, tempArray, left, center, printSteps);
            mergeSort(array, tempArray, center + 1, right, printSteps);
            merge(array, tempArray, left, center + 1, right, printSteps);
        }
    }

    /**
     * Internal method to merge two sorted halves of a subarray.
     * 
     * @param array
     *            the original array to sort.
     * @param tempArray
     *            an array to place the merged result.
     * @param leftIdx
     *            the left-most index of the subarray.
     * @param rightIdx
     *            the index of the start of the second half.
     * @param rightEnd
     *            the right-most index of the subarray.
     * @param printSteps
     *            whether to print sort progress.
     */
    private static void merge(int[] array, int[] tempArray, int leftIdx,
            int rightIdx, int rightEnd, boolean printSteps) {
        int leftEnd = rightIdx - 1;
        int tempIdx = leftIdx;
        int tempIdx2 = tempIdx;
        int numElements = rightEnd - leftIdx + 1;

        if (printSteps) {
            System.out.print("Merged ");
            System.out.print(printList(array, leftIdx, leftEnd - leftIdx + 1));
            System.out.print(" and ");
            System.out
                    .print(printList(array, rightIdx, rightEnd - rightIdx + 1));
        }

        // main loop
        while (leftIdx &lt;= leftEnd && rightIdx &lt;= rightEnd) {
            if (array[leftIdx] &lt; array[rightIdx]) {
                tempArray[tempIdx++] = array[leftIdx++];
            } else {
                tempArray[tempIdx++] = array[rightIdx++];
            }
        }

        // copy rest of left half
        while (leftIdx &lt;= leftEnd) {
            tempArray[tempIdx++] = array[leftIdx++];
        }

        // copy rest of right half
        while (rightIdx &lt;= rightEnd) {
            tempArray[tempIdx++] = array[rightIdx++];
        }

        if (printSteps) {
            System.out.print(" into ");
            System.out.println(printList(tempArray, tempIdx2, tempIdx
                    - tempIdx2));
        }

        // copy tempArray back
        for (int i = 0; i &lt; numElements; ++i, --rightEnd) {
            array[rightEnd] = tempArray[rightEnd];
        }
    }

    /**
     * Run Shellsort-A on a set.
     */
    public static double shellSortA(int[] set, boolean printSteps) {

        // Print the input set if we are asked to.
        if (printSteps) {
            System.out.println("SHELLSORT-A");
            System.out.println(printList(set));
        }

        // DO SHELLSORT-A HERE!
        // Print progress if printSteps is set to true.
        double result = shellSort(set, 1.0 / 2.0, printSteps);

        // Print the output set if we are asked to.
        if (printSteps) {
            System.out.println(printList(set));
            System.out.println("-=-=-=-=-=-=-=-");
        }

        return result;
    }

    /**
     * Run Shellsort-B on a set.
     */
    public static double shellSortB(int[] set, boolean printSteps) {

        // Print the input set if we are asked to.
        if (printSteps) {
            System.out.println("SHELLSORT-B");
            System.out.println(printList(set));
        }

        // DO SHELLSORT-B HERE!
        // Print progress if printSteps is set to true.
        double result = shellSort(set, 1.0 / 3.0, printSteps);

        // Print the output set if we are asked to.
        if (printSteps) {
            System.out.println(printList(set));
            System.out.println("-=-=-=-=-=-=-=-");
        }

        return result;
    }

    /**
     * Internal method, run Shellsort on a set.
     */
    private static double shellSort(int[] set, double reductionRatio,
            boolean printSteps) {

        // Mark the start time.
        double startTime = System.currentTimeMillis();

        int length = set.length;

        // print gap sequence
        if (printSteps) {
            System.out.print("GAP SEQUENCE:");
            for (int gap = length / 2; gap > 0; gap *= reductionRatio) {
                System.out.print(" " + gap);
            }
            System.out.println();
        }

        for (int gap = length / 2; gap > 0; gap *= reductionRatio) {

            // print the slices before sort in current interval
            if (printSteps) {
                System.out.println("Gap: " + gap);
                for (int i = 0; i &lt; gap; ++i) {
                    if (printSteps) {
                        System.out.print("Slice before:");
                        for (int j = i; j &lt; length; j += gap) {
                            System.out.print(" " + set[j]);
                        }
                        System.out.println();
                    }
                }
            }

            // sort the slices
            for (int i = gap; i &lt; length; ++i) {

                // avoids explicit swap
                int temp = set[i];
                int j = i;

                for (; (j >= gap) && (temp &lt; set[j - gap]); j -= gap) {
                    set[j] = set[j - gap];
                }
                set[j] = temp;
            }

            // print the slices after sort in current interval
            if (printSteps) {
                for (int i = 0; i &lt; gap; ++i) {
                    if (printSteps) {
                        System.out.print("Slice after:");
                        for (int j = i; j &lt; length; j += gap) {
                            System.out.print(" " + set[j]);
                        }
                        System.out.println();
                    }
                }
            }
        }

        // Mark the finish time and return the time it took to sort.
        return System.currentTimeMillis() - startTime;
    }

    private static final int CUTOFF = 10;

    public static double quickSortA(int[] set, boolean printSteps) {
        // Mark the start time.
        double startTime = System.currentTimeMillis();

        // Print the input set if we are asked to.
        if (printSteps) {
            System.out.println("QUICKSORT-A");
            System.out.println(printList(set));
        }

        // DO QUICKSORT-A HERE!
        // Print progress if printSteps is set to true.
        _quickSortA(set, 0, set.length - 1, printSteps);

        // Print the output set if we are asked to.
        if (printSteps) {
            System.out.println(printList(set));
            System.out.println("-=-=-=-=-=-=-=-");
        }

        // Mark the finish time and return the time it took to sort.
        return System.currentTimeMillis() - startTime;
    }

    private static void _quickSortA(int[] set, int left, int right,
            boolean printSteps) {
        if (printSteps) {
            System.out.println("List: " + printList(set));
        }

        if (left + CUTOFF &lt;= right) {
            // select pivot
            int center = (left + right) / 2;
            int pivot = set[center];
            if (printSteps) {
                System.out.println("Pivot: " + pivot);
            }

            // place pivot at position right
            set[center] = set[right];
            set[right] = pivot;

            // Begin partitioning
            int i = left - 1;
            int j = right;
            while (true) {
                while (set[++i] &lt; pivot) { }
                while ((j > left) && (set[--j] > pivot)) { }
                if (i &lt; j) {
                    if (printSteps) {
                        System.out.println("Pair to swap: " + set[i] + ", "
                                + set[j]);
                    }
                    swap(set, i, set, j);
                } else {
                    break;
                }
            }

            if (printSteps) {
                System.out.println("Pair to swap: " + set[i] + ", "
                        + set[right]);
            }
            swap(set, i, set, right); // Restore pivot

            _quickSortA(set, left, i - 1, printSteps); // Sort small elements
            _quickSortA(set, i + 1, right, printSteps); // Sort large elements
        } else {
            insertionSort(set, left, right, false);
        }
    }

    public static double quickSortB(int[] set, boolean printSteps) {
        // Mark the start time.
        double startTime = System.currentTimeMillis();

        // Print the input set if we are asked to.
        if (printSteps) {
            System.out.println("QUICKSORT-B");
            System.out.println(printList(set));
        }

        // DO QUICKSORT-B HERE!
        // Print progress if printSteps is set to true.
        _quickSortB(set, 0, set.length - 1, printSteps);

        // Print the output set if we are asked to.
        if (printSteps) {
            System.out.println(printList(set));
            System.out.println("-=-=-=-=-=-=-=-");
        }

        // Mark the finish time and return the time it took to sort.
        return System.currentTimeMillis() - startTime;
    }

    private static void _quickSortB(int[] set, int left, int right,
            boolean printSteps) {
        if (printSteps) {
            System.out.println("List: " + printList(set));
        }

        if (left + CUTOFF &lt;= right) {
            // median3 implicitly places pivot at position right-1
            int pivot = median3(set, left, right);
            if (printSteps) {
                System.out.println("Pivot: " + pivot);
            }

            // begin partitioning
            int i = left;
            int j = right - 1;

            while (true) {
                while (set[++i] &lt; pivot) { }
                while (set[--j] > pivot) { }
                if (i &lt; j) {
                    if (printSteps) {
                        System.out.println("Pair to swap: " + set[i] + ", "
                                + set[j]);
                    }
                    swap(set, i, set, j);
                } else {
                    break;
                }
            }

            if (printSteps) {
                System.out.println("Pair to swap: " + set[i] + ", "
                        + set[right - 1]);
            }
            swap(set, i, set, right - 1); // restore pivot

            _quickSortB(set, left, i - 1, printSteps);
            _quickSortB(set, i + 1, right, printSteps);
        } else {
            insertionSort(set, left, right, false);
        }
    }

    public static double quickSortC(int[] set, boolean printSteps) {
        // Mark the start time.
        double startTime = System.currentTimeMillis();

        // Print the input set if we are asked to.
        if (printSteps) {
            System.out.println("QUICKSORT-C");
            System.out.println(printList(set));
        }

        // DO QUICKSORT-C HERE!
        // Print progress if printSteps is set to true.
        _quickSortC(set, 0, set.length - 1, printSteps);

        // Print the output set if we are asked to.
        if (printSteps) {
            System.out.println(printList(set));
            System.out.println("-=-=-=-=-=-=-=-");
        }

        // Mark the finish time and return the time it took to sort.
        return System.currentTimeMillis() - startTime;
    }

    private static void _quickSortC(int[] set, int left, int right,
            boolean printSteps) {
        if (printSteps) {
            System.out.println("List: " + printList(set));
        }

        if (left + CUTOFF &lt;= right) {
            // median5 implicitly places pivot at position right-1
            int pivot = median5(set, left, right);
            if (printSteps) {
                System.out.println("Pivot: " + pivot);
            }

            // begin partitioning
            int i = left;
            int j = right - 1;

            while (true) {
                while (set[++i] &lt; pivot) { }
                while (set[--j] > pivot) { }
                if (i &lt; j) {
                    if (printSteps) {
                        System.out.println("Pair to swap: " + set[i] + ", "
                                + set[j]);
                    }
                    swap(set, i, set, j);
                } else {
                    break;
                }
            }

            if (printSteps) {
                System.out.println("Pair to swap: " + set[i] + ", "
                        + set[right - 1]);
            }
            swap(set, i, set, right - 1); // restore pivot

            _quickSortC(set, left, i - 1, printSteps);
            _quickSortC(set, i + 1, right, printSteps);
        } else {
            insertionSort(set, left, right, false);
        }
    }

    public static double quickSortD(int[] set, boolean printSteps) {
        // Mark the start time.
        double startTime = System.currentTimeMillis();

        // Print the input set if we are asked to.
        if (printSteps) {
            System.out.println("QUICKSORT-D");
            System.out.println(printList(set));
        }

        // DO QUICKSORT-D HERE!
        // Print progress if printSteps is set to true.
        _quickSortD(set, 0, set.length - 1, printSteps);

        // Print the output set if we are asked to.
        if (printSteps) {
            System.out.println(printList(set));
            System.out.println("-=-=-=-=-=-=-=-");
        }

        // Mark the finish time and return the time it took to sort.
        return System.currentTimeMillis() - startTime;
    }

    private static void _quickSortD(int[] set, int left, int right,
            boolean printSteps) {
        if (printSteps) {
            System.out.println("List: " + printList(set));
        }

        if (left + CUTOFF &lt;= right) {
            // use quick select to find the actual median as pivot
            // the pivot is placed at position center
            int pivot = quickSelectMedian(set, left, right, printSteps);
            if (printSteps) {
                System.out.println("Pivot: " + pivot);
            }

            // place pivot at position right
            int center = left + (right - left) / 2;
            set[center] = set[right];
            set[right] = pivot;

            // Begin partitioning
            int i = left - 1;
            int j = right;
            while (true) {
                while (set[++i] &lt; pivot) { }
                while ((j > left) && (set[--j] > pivot)) { }
                if (i &lt; j) {
                    if (printSteps) {
                        System.out.println("Pair to swap: " + set[i] + ", "
                                + set[j]);
                    }
                    swap(set, i, set, j);
                } else {
                    break;
                }
            }

            if (printSteps) {
                System.out.println("Pair to swap: " + set[i] + ", "
                        + set[right]);
            }
            swap(set, i, set, right); // Restore pivot

            _quickSortD(set, left, i - 1, printSteps); // Sort small elements
            _quickSortD(set, i + 1, right, printSteps); // Sort large elements
        } else {
            insertionSort(set, left, right, false);
        }
    }

    private static int median3(int[] set, int left, int right) {
        int center = (left + right) / 2;

        // sort the subarray of left-center-right
        if (set[center] &lt; set[left]) {
            swap(set, left, set, center);
        }
        if (set[right] &lt; set[left]) {
            swap(set, left, set, right);
        }
        if (set[right] &lt; set[center]) {
            swap(set, center, set, right);
        }

        // place pivot at position right-1
        swap(set, center, set, right - 1);
        return set[right - 1];
    }

    // a hack to reduce memory allocation time
    private static int[] _tempArrayForMedian5 = new int[5];

    private static int median5(int[] set, int left, int right) {
        int center = (left + right) / 2;
        int leftCenter = (left + center) / 2;
        int rightCenter = (center + right) / 2;

        // sort the subarray of
        // left-leftCenter-center-rightCenter-rightCenter
        _tempArrayForMedian5[0] = set[left];
        _tempArrayForMedian5[1] = set[leftCenter];
        _tempArrayForMedian5[2] = set[center];
        _tempArrayForMedian5[3] = set[rightCenter];
        _tempArrayForMedian5[4] = set[right];
        insertionSort(_tempArrayForMedian5, false);

        // copy the sort results back to the input array
        // and place the pivot at position right-1
        set[left] = _tempArrayForMedian5[0];
        set[leftCenter] = _tempArrayForMedian5[1];
        set[center] = set[right - 1];
        set[right - 1] = _tempArrayForMedian5[2];
        set[rightCenter] = _tempArrayForMedian5[3];
        set[right] = _tempArrayForMedian5[4];

        return set[right - 1];
    }

    public static int quickSelectMedian(int[] set, int left, int right,
            boolean printSteps) {
        int k = (right - left) / 2 + 1; // expected median's index as k
        quickSelect(set, left, right, k, printSteps);
        return set[left + k - 1];
    }

    /**
     * Internal selection method that makes recursive calls. Uses
     * median-of-three partitioning and a cutoff of 10. Places the kth smallest
     * item in set[k-1]. NOTE: This method will modify the input array's order.
     * 
     * @param set
     *            the input array of int.
     * @param left
     *            the left-most index of the subarray.
     * @param right
     *            the right-most index of the subarray.
     * @param k
     *            the desired rank (1 is minimum) in the entire array.
     */
    private static void quickSelect(int[] set, int left, int right, int k,
            boolean printSteps) {
        if (left + CUTOFF &lt;= right) {
            int pivot = median3(set, left, right);

            // begin partitioning
            int i = left;
            int j = right - 1;
            while (true) {
                while (set[++i] &lt; pivot) { }
                while (set[--j] > pivot) { }
                if (i &lt; j) {
                    if (printSteps) {
                        System.out.println("Pair to swap: " + set[i] + ", "
                                + set[j]);
                    }
                    swap(set, i, set, j);
                } else {
                    break;
                }
            }

            if (printSteps) {
                System.out.println("Pair to swap: " + set[i] + ", "
                        + set[right - 1]);
            }
            swap(set, i, set, right - 1); // restore pivot

            if (k - 1 &lt; i) {
                quickSelect(set, left, i - 1, k, printSteps);
            } else if (k - 1 > i) {
                quickSelect(set, i + 1, right, k, printSteps);
            }
        } else {
            // do an insertion sort on the subarray
            insertionSort(set, left, right, false);
        }
    }

    /**
     * Return a rendering of a list as a StringBuffer. You can pass the buffer
     * to a System.out.println() to actually print the set.
     */
    private static StringBuffer printList(int[] set) {
        return printList(set, 0, set.length);
    }

    private static StringBuffer printList(int[] set, int beginIdx, int length) {
        StringBuffer result = new StringBuffer();

        for (int i = 0; i &lt; length; i++) {
            result.append(set[beginIdx++]);

            // Add spaces between elements
            if (i &lt; (length - 1)) {
                result.append(" ");
            }
        }

        return result;
    }

    private static final void swap(int[] src, int srcIdx, int[] dst, int dstIdx) {
        int temp = src[srcIdx];
        src[srcIdx] = dst[dstIdx];
        dst[dstIdx] = temp;
    }
}</pre><br /><br />AutomateSortComparisonReport.java: see attached file.<br /><br />Uses JFreeChart 1.0.1 for charting. Visit <a href="http://www.jfree.org/jfreechart/" target="_blank">http://www.jfree.org/jfreechart/</a> for more information on JFreeChart.<br /><br />Sample plot graphs of this project can be found here: <a href="http://rednaxelafx.javaeye.com/blog/174063" target="_blank">http://rednaxelafx.javaeye.com/blog/174063</a>
          <br/><br/>
          <span style="color:red;">
            <a href="http://ravenex.javaeye.com/blog/175557#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 24 Mar 2008 20:27:47 +0800</pubDate>
        <link>http://ravenex.javaeye.com/blog/175557</link>
        <guid>http://ravenex.javaeye.com/blog/175557</guid>
      </item>
          <item>
        <title>字符串变异的演示</title>
        <author>ravenex</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ravenex.javaeye.com">ravenex</a>&nbsp;
                    链接：<a href="http://ravenex.javaeye.com/blog/175551" style="color:red;">http://ravenex.javaeye.com/blog/175551</a>&nbsp;
          发表时间: 2008年03月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="quote_title">引用</div><div class="quote_div"><strong>Programming: String Mutation</strong><br /><br />Richard Dawkins, in his book The Blind Watchmaker, explains his much-debated experiment known as the weasel program. This algorithm is designed to show that random mutations in DNA can create complex life forms through natural selection, rather than the will of an intelligent designer. His experiment took a sample string of gibberish and repeatedly mutated, or slightly changed, the string as if introducing an error in DNA duplication from one generation to another. The program had a "target" string in mind -- a line from Hamlet, "Methinks it is like a weasel" -- and continued until the random mutations added up such that the original string was the same as this target string. By running his program and finding that any line of gibberish can become Shakespeare through incremental changes, Dawkins suggested that natural selection can account for all the complexity of life.<br /><br />Naturally, this is a controversial experiment, and an over-simplification of evolution. One criticism is that it is designed to run toward a target string; at every generation, a string's "fitness" to reproduce is determined by its similarity to the target. Could the target not be determined by an intelligent designer? And is an organism's fitness to survive proportional in such small increments to its genetic similarity with a better-adapted mutant? Whatever the answer, Dawkins probably did not anticipate that his experiment was an early example of what has become a common technique in machine learning: genetic algorithms. GAs can apply the same strategy effectively to complicated problems in artifical intelligence: come up with a model, make a lot of "daughter" models that are slightly different, choose the daughter that works a little bit better than the original model, and make her the new mother for the next generation. Lather, rinse, repeat.<br /><br />For HW2 programming we're going to try our hand at genetic algorithms, using the same string-to-string transformation goal. Specifically, the steps of your program should be: <br />Take from the user, on the command line, two strings: an input string to start from, and a target string toward which to mutate. (Hint: when testing on CUNIX, you can use quotation marks to pass command line arguments with spaces. See example output.) <br />Model the input word as a linked list of letters (Strings of length 1), using Java's Linked List class. <br />Create a large set of mutated "daughter" strings from the input string, each of which is different in a small way: <br />Insertion. For each of 27 letters (including space), and each of N+1 positions in the input string, insert the letter into the word at the position. Use the add() method of LinkedList that takes an index to quickly insert the letter at the correct position. For a string of N letters, this method will produce 27 * (N+1) daughter strings. For example HELLO becomes AHELLO, BHELLO, etc., until HELLOZ (not counting the space character). <br />Deletion. For each letter in the input string, delete the letter. Use the remove() method of LinkedList() to do this quickly. For a string of N letters, this method will produce N daughter strings. For example, HELLO becomes ELLO, HLLO, HELO (twice) and HELL. <br />Choose the daughter string that is closest to the target string. To do this, use an algorithm to find each daughter string's fitness -- a score between 0 and 1 -- and find the daughter string with the highest score. <br />Fitness should be calculated as the length of the longest common substring of the target string found in the input string, divided by the length of the target string. For example, HPPLE has a score of .8 compared to APPLE, since the longest substring of APPLE found in HPPLE is 4 letters long, which is .8 of APPLE's length. Additionally, penalize the score by 0.1 for each extraneous letter the input string has over the length of the target string. For example. HAPPLE has a score of .9 compared to APPLE, because it is 1 letter longer, and otherwise has the complete substring APPLE. Note that this makes it possible for a candidate word to have a negative score. <br />Print out the generation number, the winning daughter string and her score. <br />Repeat the above from step 2, making the winning daughter the new input string, until the daughter has reached the target string. You can use either iteration or recursion to repeat appropriately. Then, terminate the program. <br />Here are some hints and guidelines for your program: <br />Let's be a little more formal about object-oriented design in HW2. Set up a class called Word which will represent a single word. The class should: <br />Translate an input string into a LinkedList in the constructor. It should take a String as an argument in the constructor, have a private LinkedList as a variable, and parse the string into the LinkedList (using the substring() method of String). <br />Have a method, mutate, which returns an array of all daughter Words to be sired by the target string. That is, each daughter should be a new Word. <br />Have a method makeCopy() that duplicates itself into an identical Word. Your mutate() function will use this to create many copies of itself and then change each copy. <br />Have a method toString() that creates a normal string from the LinkedList and returns it. (Hint: use a StringBuffer.) <br />Have one other class, MutationSim, that takes the input and target strings from the user, creates a Word from the target, mutates it, calculates fitness, and repeats as described above. <br />Learn about the String methods substring(), toUpperCase() and indexOf(). <br />It'll help if you create a function that returns all the letter of the alphabet in an array over which you can iterate in a loop... something maybe like this: <br /><pre name="code" class="java">public static String[] alphabet () {
   String[] alphabet = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", " "};
   return alphabet;
}</pre><br /><br />Answer the following questions in your README: <br />How did you design your program? What design choices did you make in setting up your algorithm, other than the ones specified above? <br />How long does your program take? What do you think is the maximum number of generations needed to reach the target string, i.e., Big-Oh for an input string of I letters, a target string of T letters and an alphabet of L letters? Is this also the minimum generations needed? Why or why not? <br />How does the total run time relate to you answer to #2? How do you see your program's performance change as you increase the length of the strings? <br />Do you think the fitness function was a fair model of natural selection? Why or why not? How would you improve it? <br /><br />Example Output<br /><pre name="code" class="java">$ java MutationSim "Hello there" "How are you"
Generation 1: ELLO THERE (score: 0.18181818181818182)
Generation 2: ELLOW THERE (score: 0.2727272727272727)
Generation 3: LLOW THERE (score: 0.2727272727272727)
Generation 4: LLHOW THERE (score: 0.36363636363636365)
Generation 5: LHOW THERE (score: 0.36363636363636365)
Generation 6: LHOW ATHERE (score: 0.45454545454545453)
Generation 7: HOW ATHERE (score: 0.45454545454545453)
Generation 8: HOW ARTHERE (score: 0.5454545454545454)
Generation 9: HOW ARHERE (score: 0.5454545454545454)
Generation 10: HOW ARERE (score: 0.6363636363636364)
Generation 11: HOW ARE RE (score: 0.7272727272727273)
Generation 12: HOW ARE YRE (score: 0.8181818181818182)
Generation 13: HOW ARE YE (score: 0.8181818181818182)
Generation 14: HOW ARE YOE (score: 0.9090909090909091)
Generation 15: HOW ARE YO (score: 0.9090909090909091)
Generation 16: HOW ARE YOU (score: 1.0)</pre><br /><br /><pre name="code" class="java">$ java MutationSim "it was a dark and stormy night" "to be or not to be"
Generation 1: IT WAS A DARK AND TORMY NIGHT (score: -0.9333333333333335)
Generation 2: T WAS A DARK AND TORMY NIGHT (score: -0.8333333333333334)
Generation 3:  WAS A DARK AND TORMY NIGHT (score: -0.7333333333333334)
Generation 4: WAS A DARK AND TORMY NIGHT (score: -0.6333333333333334)
Generation 5: AS A DARK AND TORMY NIGHT (score: -0.5333333333333334)
Generation 6: S A DARK AND TORMY NIGHT (score: -0.43333333333333346)
Generation 7:  A DARK AND TORMY NIGHT (score: -0.33333333333333337)
Generation 8: A DARK AND TORMY NIGHT (score: -0.23333333333333336)
Generation 9:  DARK AND TORMY NIGHT (score: -0.1333333333333334)
Generation 10: DARK AND TORMY NIGHT (score: -0.033333333333333354)
Generation 11: ARK AND TORMY NIGHT (score: 0.06666666666666665)
Generation 12: RK AND TORMY NIGHT (score: 0.16666666666666666)
Generation 13: K AND TORMY NIGHT (score: 0.16666666666666666)
Generation 14: K ANDT TORMY NIGHT (score: 0.2222222222222222)
Generation 15:  ANDT TORMY NIGHT (score: 0.2222222222222222)
Generation 16:  ANDOT TORMY NIGHT (score: 0.2777777777777778)
Generation 17:  ANOT TORMY NIGHT (score: 0.3333333333333333)
Generation 18:  NOT TORMY NIGHT (score: 0.3888888888888889)
Generation 19: R NOT TORMY NIGHT (score: 0.4444444444444444)
Generation 20: OR NOT TORMY NIGHT (score: 0.5)
Generation 21: OR NOT TOMY NIGHT (score: 0.5)
Generation 22:  OR NOT TOMY NIGHT (score: 0.5555555555555556)
Generation 23:  OR NOT TOY NIGHT (score: 0.5555555555555556)
Generation 24:  OR NOT TO NIGHT (score: 0.6111111111111112)
Generation 25: E OR NOT TO NIGHT (score: 0.6666666666666666)
Generation 26: BE OR NOT TO NIGHT (score: 0.7222222222222222)
Generation 27: BE OR NOT TO IGHT (score: 0.7222222222222222)
Generation 28:  BE OR NOT TO IGHT (score: 0.7777777777777778)
Generation 29:  BE OR NOT TO GHT (score: 0.7777777777777778)
Generation 30: O BE OR NOT TO GHT (score: 0.8333333333333334)
Generation 31: O BE OR NOT TO HT (score: 0.8333333333333334)
Generation 32: TO BE OR NOT TO HT (score: 0.8888888888888888)
Generation 33: TO BE OR NOT TO T (score: 0.8888888888888888)
Generation 34: TO BE OR NOT TO BT (score: 0.9444444444444444)
Generation 35: TO BE OR NOT TO B (score: 0.9444444444444444)
Generation 36: TO BE OR NOT TO BE (score: 1.0)</pre><br /><br /><pre name="code" class="java">$ java MutationSim asafsdfkurweafasfp "methinks it is like a weasel"
Generation 1: ASAFSDFKUR WEAFASFP (score: 0.14285714285714285)
Generation 2: ASAFSDFKURA WEAFASFP (score: 0.17857142857142858)
Generation 3: ASAFSDFKUR A WEAFASFP (score: 0.21428571428571427)
Generation 4: ASAFSDFKURE A WEAFASFP (score: 0.25)
Generation 5: ASAFSDFKURKE A WEAFASFP (score: 0.2857142857142857)
Generation 6: ASAFSDFKURIKE A WEAFASFP (score: 0.32142857142857145)
Generation 7: ASAFSDFKURLIKE A WEAFASFP (score: 0.35714285714285715)
Generation 8: ASAFSDFKUR LIKE A WEAFASFP (score: 0.39285714285714285)
Generation 9: ASAFSDFKURS LIKE A WEAFASFP (score: 0.42857142857142855)
Generation 10: ASAFSDFKURIS LIKE A WEAFASFP (score: 0.4642857142857143)
Generation 11: SAFSDFKURIS LIKE A WEAFASFP (score: 0.4642857142857143)
Generation 12: SAFSDFKUR IS LIKE A WEAFASFP (score: 0.5)
Generation 13: AFSDFKUR IS LIKE A WEAFASFP (score: 0.5)
Generation 14: AFSDFKURT IS LIKE A WEAFASFP (score: 0.5357142857142857)
Generation 15: FSDFKURT IS LIKE A WEAFASFP (score: 0.5357142857142857)
Generation 16: FSDFKURIT IS LIKE A WEAFASFP (score: 0.5714285714285714)
Generation 17: SDFKURIT IS LIKE A WEAFASFP (score: 0.5714285714285714)
Generation 18: SDFKUR IT IS LIKE A WEAFASFP (score: 0.6071428571428571)
Generation 19: DFKUR IT IS LIKE A WEAFASFP (score: 0.6071428571428571)
Generation 20: DFKURS IT IS LIKE A WEAFASFP (score: 0.6428571428571429)
Generation 21: FKURS IT IS LIKE A WEAFASFP (score: 0.6428571428571429)
Generation 22: FKURKS IT IS LIKE A WEAFASFP (score: 0.6785714285714286)
Generation 23: KURKS IT IS LIKE A WEAFASFP (score: 0.6785714285714286)
Generation 24: KURNKS IT IS LIKE A WEAFASFP (score: 0.7142857142857143)
Generation 25: URNKS IT IS LIKE A WEAFASFP (score: 0.7142857142857143)
Generation 26: URINKS IT IS LIKE A WEAFASFP (score: 0.75)
Generation 27: RINKS IT IS LIKE A WEAFASFP (score: 0.75)
Generation 28: RHINKS IT IS LIKE A WEAFASFP (score: 0.7857142857142857)
Generation 29: HINKS IT IS LIKE A WEAFASFP (score: 0.7857142857142857)
Generation 30: THINKS IT IS LIKE A WEAFASFP (score: 0.8214285714285714)
Generation 31: THINKS IT IS LIKE A WEAASFP (score: 0.8214285714285714)
Generation 32: THINKS IT IS LIKE A WEASFP (score: 0.8571428571428571)
Generation 33: ETHINKS IT IS LIKE A WEASFP (score: 0.8928571428571429)
Generation 34: METHINKS IT IS LIKE A WEASFP (score: 0.9285714285714286)
Generation 35: METHINKS IT IS LIKE A WEASP (score: 0.9285714285714286)
Generation 36: METHINKS IT IS LIKE A WEASEP (score: 0.9642857142857143)
Generation 37: METHINKS IT IS LIKE A WEASE (score: 0.9642857142857143)
Generation 38: METHINKS IT IS LIKE A WEASEL (score: 1.0)</pre></div><br /><br />MutationSim.java:<br /><pre name="code" class="java">/*
 * MutationSim.java, 02/22/2008
 */

public class MutationSim {

    private String input;
    private String target;

    private static String USAGE = "Usage: java MutationSim INPUT_STRING TARGET_STRING"
        + "\nOnly English alphabet and space is allowed in the strings.";

    public static void main(String[] args) {
        MutationSim sim = new MutationSim();
        try {
            sim.processCommandLine(args);
            sim.runSim();
        } catch (Exception e) {
            System.err.println(e.getMessage());
            e.printStackTrace(System.err);
            usage();
        }
    }

    private void processCommandLine(String[] args) throws Exception {
        if (args.length > 2)
            throw new Exception("Too many arguments.");
        if (args.length &lt; 2)
            throw new Exception("Too little arguments.");
        if (isNonAlphabetExist(args[0]) || isNonAlphabetExist(args[1]))
            throw new Exception("Non-English alphabet character in string.");

        this.input = args[0];
        this.target = args[1];
    }

    void runSim() {
        Word word = new Word(this.input);
        Word targetWord = new Word(this.target);
        Word currentWord = null;
        double score = -2.0; // dummy value

        for (int generation = 1; score != 1.0; ++generation) {
            Word[] daughters = word.mutate();

            // iterate through the array,
            // do a linear search for best fit
            double maxFitness = -2.0;
            for (Word w : daughters) {
                double currentFitness = calculateFitness(w, targetWord);

                if (maxFitness &lt;= currentFitness) {
                    currentWord = w;
                    maxFitness = currentFitness;
                }
            }

            printStat(generation, currentWord, maxFitness);
            word = currentWord;
            score = maxFitness;
        }
    }

    static void usage() {
        System.err.println();
        System.err.println(USAGE);
    }

    static void printStat(int generation, Word word, double score) {
        System.out.println("Generation " + generation + ": " + word.toString()
                + " {score: " + score + ")");
    }

    public static double calculateFitness(Word in, Word targ) {
        double ratio = Util.longestCommonSubstring(in.toString(),
                targ.toString()).length()
                / (double) targ.length();
        double penalty =
            (in.length() > targ.length()) ?
                (0.1 * (in.length() - targ.length()))
                : 0;
        return ratio - penalty;
    }
    
    private static boolean isNonAlphabetExist(String s) {
        s = s.toUpperCase();
        String[] alphabet = Util.alphabet();
        
        for (String letter : alphabet) {
            s = s.replaceAll(letter, "");
        }

        return (s.length() != 0);
    }
}</pre><br /><br />Word.java:<br /><pre name="code" class="java">/*
 * Word.java, 02/22/2008
 */

import java.util.ArrayList;
import java.util.LinkedList;

/**
 * 
 */
public class Word {
    private LinkedList&lt;String> list;

    public Word() {
        // list = null;
    }

    public Word(String input) {
        list = new LinkedList&lt;String>();
        
        for (int i = 0; i &lt; input.length(); ++i) {
            String currentLetter = input.substring(i, i+1);
            list.add(currentLetter.toUpperCase());
        }
    }

    public Word[] mutate() {
        String[] alphabet = Util.alphabet();
        int wordLength = this.list.size();
        int alphabetLength = alphabet.length;
        int arraySize = (wordLength + 1) * alphabetLength + wordLength;
        Word[] result = new Word[arraySize];
        int index = 0;

        for (int i = 0; i &lt;= wordLength; ++i) {
            // insertion
            for (int j = 0; j &lt; alphabetLength; ++j) {
                Word copy = this.makeCopy();
                copy.list.add(i, alphabet[j]);
                result[index++] = copy;
            }

            // deletion
            if (i &lt; this.list.size()) {
                Word copy = this.makeCopy();
                copy.list.remove(i);
                result[index++] = copy;
            }
        }

        return result;
    }

    public Word makeCopy() {
        Word copy = new Word();
        copy.list = (LinkedList&lt;String>) this.list.clone();
        return copy;
    }
    
    public int length() {
        return this.list.size();
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        for (String str : list) {
            builder.append(str);
        }

        return builder.toString();
    }
}</pre><br /><br />Util.java:<br /><pre name="code" class="java">
public class Util {
    
    /**
     * Returns the longest common substring of the given two arguments.
     * 
     * @param first the first string
     * @param second the second string
     * @return the longest common substring of the given two arguments
     */
    public static String longestCommonSubstring(String first, String second) {
        // could have used dynamic programming, or generalized suffix tree
        // to solve the LCS problem, but here we'll just stick to simplicity
        
        int start = 0; // The start in a of the longest found so far
        int len = 0; // The length of the longest found so far
        for (int i = 0; i &lt; first.length() - len; ++i) {
            for (int j = first.length(); j > i + len; --j) {
                if (second.indexOf(first.substring(i, j)) != -1) {
                    start = i;
                    len = j - i;
                    break; // Exit the inner loop
                }
            }
        }

        return first.substring(start, start + len);
    }
    
    public static String[] alphabet() {
        String[] alphabet = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
                "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
                "W", "X", "Y", "Z", " " };
        return alphabet;
    }
}</pre>
          <br/><br/>
          <span style="color:red;">
            <a href="http://ravenex.javaeye.com/blog/175551#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 24 Mar 2008 20:12:28 +0800</pubDate>
        <link>http://ravenex.javaeye.com/blog/175551</link>
        <guid>http://ravenex.javaeye.com/blog/175551</guid>
      </item>
          <item>
        <title>生日悖论的模拟</title>
        <author>ravenex</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://ravenex.javaeye.com">ravenex</a>&nbsp;
                    链接：<a href="http://ravenex.javaeye.com/blog/161348" style="color:red;">http://ravenex.javaeye.com/blog/161348</a>&nbsp;
          发表时间: 2008年02月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="quote_title">引用</div><div class="quote_div"><strong>Programming: The Birthday Paradox</strong><br /><br />There's a parlor trick known as the Birthday Paradox where in any group of 23 or more people, chances are more than 50% that some two people have the same birthday. This is counter-intuitive to statistical lay people, but can be proven mathematically. Still, certain lay people have been known to be suspicious of math (but rather trusting of computers), so one thing we can do is gather empirical evidence -- simulate gatherings of people with randomly-assigned birthdays and test how often two people end up with the same birthday. We'd also like to vary the problem a bit to see what effect differently-sized calendars and group sizes have on the result.<br /><br />Your simulation should work like this: <br />1.	Take from the user two numbers: D, a calendar length (in days), and N, a number of trials.<br />2.	Picks random birthdays for G=2 guests.<br />3.	Test to see if any of the 2 guests share a birthday with another of the 2 guests. If so, the program remembers a "hit."<br />4.	Repeat steps 2 and 3 until the requested number of trials is met.<br />5.	Report the percentage of trials that reported hits, that is, the proportion of simulated parties where the some two guests shared a birthday.<br />6.	Repeat steps 2, 3, 4, and 5 for parties of 3, 4, 5 ... 100 guests.<br />Test your program on a few calendar lengths, as small as 2 days and as large as 1000 days. If your program works correctly, you should find that the percentage of hits exceeds .5 for N=365 when G=23.<br /><br />Your program should take the two variables, D and T, on the command line. Be sure to check that they are valid (both should be integers of at least 2).<br /><br />In your README, answer the following questions (in addition to the usual README content): <br />1.	How did you implement your program? What loops did you use, where, for what purpose? What data structures did you use to store your information?<br />2.	What were your results for D=2, 10, 100, 500, and 1000? Did they match up with your expectations?<br />3.	What happens to your results when you vary the number of trials? How many trials are "enough" for results to converge?<br />4.	Based on your answer to #1, how long does your program take? Give Big-Oh, Omega-Oh, and, if applicable, Theta-Oh terms as a function of D, G and T.<br /><br />Example Output<br /><pre name="code" class="java">$ java BirthdaySim 200 1000
2 guests: [0.0050]: 5 time(s) out of 1000, two guests had the same birthday
3 guests: [0.017]: 17 time(s) out of 1000, two guests had the same birthday
4 guests: [0.024]: 24 time(s) out of 1000, two guests had the same birthday
5 guests: [0.057]: 57 time(s) out of 1000, two guests had the same birthday
6 guests: [0.06]: 60 time(s) out of 1000, two guests had the same birthday
7 guests: [0.09]: 90 time(s) out of 1000, two guests had the same birthday
8 guests: [0.134]: 134 time(s) out of 1000, two guests had the same birthday
9 guests: [0.158]: 158 time(s) out of 1000, two guests had the same birthday
10 guests: [0.213]: 213 time(s) out of 1000, two guests had the same birthday
11 guests: [0.227]: 227 time(s) out of 1000, two guests had the same birthday
12 guests: [0.291]: 291 time(s) out of 1000, two guests had the same birthday
13 guests: [0.322]: 322 time(s) out of 1000, two guests had the same birthday
14 guests: [0.352]: 352 time(s) out of 1000, two guests had the same birthday
15 guests: [0.415]: 415 time(s) out of 1000, two guests had the same birthday
16 guests: [0.454]: 454 time(s) out of 1000, two guests had the same birthday
17 guests: [0.487]: 487 time(s) out of 1000, two guests had the same birthday
18 guests: [0.532]: 532 time(s) out of 1000, two guests had the same birthday
19 guests: [0.595]: 595 time(s) out of 1000, two guests had the same birthday
20 guests: [0.609]: 609 time(s) out of 1000, two guests had the same birthday
21 guests: [0.62]: 620 time(s) out of 1000, two guests had the same birthday
22 guests: [0.664]: 664 time(s) out of 1000, two guests had the same birthday
23 guests: [0.73]: 730 time(s) out of 1000, two guests had the same birthday
24 guests: [0.775]: 775 time(s) out of 1000, two guests had the same birthday
25 guests: [0.807]: 807 time(s) out of 1000, two guests had the same birthday
26 guests: [0.831]: 831 time(s) out of 1000, two guests had the same birthday
27 guests: [0.857]: 857 time(s) out of 1000, two guests had the same birthday
28 guests: [0.855]: 855 time(s) out of 1000, two guests had the same birthday
29 guests: [0.875]: 875 time(s) out of 1000, two guests had the same birthday
30 guests: [0.893]: 893 time(s) out of 1000, two guests had the same birthday
31 guests: [0.927]: 927 time(s) out of 1000, two guests had the same birthday
32 guests: [0.93]: 930 time(s) out of 1000, two guests had the same birthday
33 guests: [0.943]: 943 time(s) out of 1000, two guests had the same birthday
34 guests: [0.963]: 963 time(s) out of 1000, two guests had the same birthday
35 guests: [0.942]: 942 time(s) out of 1000, two guests had the same birthday
36 guests: [0.962]: 962 time(s) out of 1000, two guests had the same birthday
37 guests: [0.972]: 972 time(s) out of 1000, two guests had the same birthday
38 guests: [0.978]: 978 time(s) out of 1000, two guests had the same birthday
39 guests: [0.979]: 979 time(s) out of 1000, two guests had the same birthday
40 guests: [0.982]: 982 time(s) out of 1000, two guests had the same birthday
41 guests: [0.986]: 986 time(s) out of 1000, two guests had the same birthday
42 guests: [0.988]: 988 time(s) out of 1000, two guests had the same birthday
43 guests: [0.996]: 996 time(s) out of 1000, two guests had the same birthday
44 guests: [0.997]: 997 time(s) out of 1000, two guests had the same birthday
45 guests: [0.999]: 999 time(s) out of 1000, two guests had the same birthday
46 guests: [0.995]: 995 time(s) out of 1000, two guests had the same birthday
47 guests: [0.998]: 998 time(s) out of 1000, two guests had the same birthday
48 guests: [0.997]: 997 time(s) out of 1000, two guests had the same birthday
49 guests: [0.998]: 998 time(s) out of 1000, two guests had the same birthday
50 guests: [0.999]: 999 time(s) out of 1000, two guests had the same birthday
51 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
52 guests: [0.998]: 998 time(s) out of 1000, two guests had the same birthday
53 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
54 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
55 guests: [0.999]: 999 time(s) out of 1000, two guests had the same birthday
56 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
57 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
58 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
59 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
60 guests: [0.999]: 999 time(s) out of 1000, two guests had the same birthday
61 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
62 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
63 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
64 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
65 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
66 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
67 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
68 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
69 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
70 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
71 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
72 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
73 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
74 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
75 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
76 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
77 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
78 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
79 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
80 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
81 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
82 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
83 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
84 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
85 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
86 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
87 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
88 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
89 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
90 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
91 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
92 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
93 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
94 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
95 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
96 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
97 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
98 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
99 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday
100 guests: [1.0]: 1000 time(s) out of 1000, two guests had the same birthday</pre></div><br /><br />BirthdaySim.java:<br /><pre name="code" class="java">/*
 * BirthdaySim.java
 * ver 0.0.0.1, Jan 30, 2008
 */

public class BirthdaySim {

    ///////////////////////////////////////////////////////////////////////////
    // Static fields
    ///////////////////////////////////////////////////////////////////////////

    private static int          D;

    private static int          T;

    ///////////////////////////////////////////////////////////////////////////
    // Constants
    ///////////////////////////////////////////////////////////////////////////

    private static final int    MIN_GUESTS  = 2;
    private static final int    MAX_GUESTS  = 100;
    private static final String USAGE       =
        "Usage: java BirthdaySim daysOfCalendar numberOfTrials";

    ///////////////////////////////////////////////////////////////////////////
    // Program entry point
    ///////////////////////////////////////////////////////////////////////////

    /**
     * @param args Command line parameters.
     * Usage: java BirthdaySim daysOfCalendar numberOfTrials
     */
    public static void main( String[ ] args ) {
        try {
            processCommandLine( args );
            runTrials( D, T );
        } catch ( NumberFormatException nfe ) {
            System.err.println( "Invalid number format: " + nfe.getMessage( ) );
            usage( );
        } catch ( Exception e ) {
            System.err.println( e.getMessage( ) );
            usage( );
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // Helper methods
    ///////////////////////////////////////////////////////////////////////////

    private static void processCommandLine( String[ ] args ) throws Exception {
        if ( args.length > 2 )
            throw new Exception( "Too many arguments." );
        if ( args.length &lt; 2 )
            throw new Exception( "Too little arguments." );

        D = Integer.parseInt( args[ 0 ] );
        T = Integer.parseInt( args[ 1 ] );
    }

    private static void usage() {
        System.out.println( USAGE );
    }

    static void runTrials( int d, int t ) {
        for ( int i = MIN_GUESTS; i &lt;= MAX_GUESTS; ++i ) {
            Simulator sim = new Simulator( d, t, i );
            System.out.println( sim );
        }
    }
}</pre><br /><br />Simulator.java:<br /><pre name="code" class="java">/*
 * Simulator.java
 * ver 0.0.0.1, Jan 30, 2008
 */

import java.util.Arrays;
import java.util.Random;

/**
 * Implementation of birthday problem.
 */
public class Simulator {

    //////////////////////////////////////////////////////////////////////////
    // Private fields
    ///////////////////////////////////////////////////////////////////////////

    private int[ ]  guest;
    private int     daysOfCalendar;
    private int     numberOfTrials;
    private int     hitCount;
    private boolean isCalculated;

    ///////////////////////////////////////////////////////////////////////////
    // Constructors
    ///////////////////////////////////////////////////////////////////////////

    public Simulator( int daysOfCalendar, int numberOfTrials, int numberOfGuests ) {
        this.guest = new int[ numberOfGuests ];
        this.daysOfCalendar = daysOfCalendar;
        this.numberOfTrials = numberOfTrials;
        this.setCalculated( false );
    }

    ///////////////////////////////////////////////////////////////////////////
    // Methods
    ///////////////////////////////////////////////////////////////////////////

    protected void initialize( ) {
        Random random = new Random( );

        // initialize guest array
        // Theta(n), where n = this.guest.length (?)
        for ( int i = 0; i &lt; this.guest.length; ++i ) {
            this.guest[ i ] = random.nextInt( this.getDaysOfCalendar( ) );
        }
        
        // sort guest array with Java's tuned quicksort
        // implementation in standard library.
        // this is an O(n^2) and Omega(n*log(n)) algorithm,
        // where n = this.guest.length
        Arrays.sort( this.guest );
    }

    public void runTrials( ) {
        this.hitCount = 0;

        // run trials for T times
        for ( int i = 0; i &lt; this.getNumberOfTrials( ); ++i ) {
            this.initialize( );
            this.hitCount = ( this.isHit( ) ) ? this.hitCount + 1 : this.hitCount;
        }

        this.setCalculated( true );
    }
    
    private boolean isHit( ) {
        int lastNumber = this.guest[ 0 ];
        
        // do a linear search for duplicate occurences
        // Theta(n), where n = this.guest.length (?)
        for ( int i = 1; i &lt; this.guest.length; ++i ) {
            if ( lastNumber == this.guest[ i ] ) {
                return true;
            } else {
                lastNumber = this.guest[ i ];
            }
        }
        
        return false;
    }

    ///////////////////////////////////////////////////////////////////////////
    // Overridden methods
    ///////////////////////////////////////////////////////////////////////////

    @Override
    public String toString( ) {
        if ( !this.isCalculated( ) ) {
            this.runTrials( );
        }

        StringBuilder sb = new StringBuilder( );
        sb.append( this.getNumberOfGuests( ) );
        sb.append( " guests: [" );
        sb.append( this.getProbability( ) );
        sb.append( "]: " );
        sb.append( this.getHitCount( ) );
        sb.append( " time(s) out of " );
        sb.append( this.getNumberOfTrials( ) );
        sb.append( ", two guests had the same birthday" );

        return sb.toString( );
    }

    ///////////////////////////////////////////////////////////////////////////
    // Getter/Setter methods
    ///////////////////////////////////////////////////////////////////////////

    public int getNumberOfGuests( ) {
        return this.guest.length;
    }

    public void setNumberOfGuests( int numberOfGuests ) {
        this.guest = new int[ numberOfGuests ];
        this.setCalculated( false );
    }

    public int getDaysOfCalendar( ) {
        return this.daysOfCalendar;
    }

    public void setDaysOfCalendar( int daysOfCalendar ) {
        this.daysOfCalendar = daysOfCalendar;
        this.setCalculated( false );
    }

    public int getNumberOfTrials( ) {
        return this.numberOfTrials;
    }

    public void setNumberOfTrials( int numberOfTrials ) {
        this.numberOfTrials = numberOfTrials;
        this.setCalculated( false );
    }

    public int getHitCount( ) {
        return hitCount;
    }

    public double getProbability( ) {
        if ( !this.isCalculated( ) ) {
            this.runTrials( );
        }

        return this.hitCount / ( double ) this.numberOfTrials;
    }

    private boolean isCalculated( ) {
        return this.isCalculated;
    }

    private void setCalculated( boolean isCalculated ) {
        this.isCalculated = isCalculated;
        if ( !this.isCalculated ) {
            this.hitCount = -1;
        }
    }
    
    ///////////////////////////////////////////////////////////////////////////
    // main, for testing purpose only
    ///////////////////////////////////////////////////////////////////////////
    
    public static void main( String[ ] args ) {
        Simulator sim = new Simulator( 200, 1000, 23 );
        System.out.println( sim );
    }
}</pre>
          <br/><br/>
          <span style="color:red;">
            <a href="http://ravenex.javaeye.com/blog/161348#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 03 Feb 2008 21:54:29 +0800</pubDate>
        <link>http://ravenex.javaeye.com/blog/161348</link>
        <guid>http://ravenex.javaeye.com/blog/161348</guid>
      </item>
      </channel>
</rss>