Implements QuickSort three different ways : Sort Search « Collections Data Structure « Java






Implements QuickSort three different ways

     
//package proj6;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Implements QuickSort three different ways:
 * 1. Perform the basic, sequential QuickSort algorithm with two-pointer
 *    partition.
 * 2. Perform QuickSort using four threads, explicitely created and invoked.
 * 3. Perform QuickSort on numThreads using Executor support from Java's
 *    concurrency libraries.
 *
 * The program can be executed with the following command:
 * Usage: java Project6 <part> [OPTIONS]
 * <part> - Valid parts are 1, 2, or 3
 *
 * Available options:
 * -s, --size    The size of the array to generate
 * -r, --random  True indicates a random array, false indicates a seeded array
 * -m, --max     Random numbers will generated between 0 (inclusive) and
 *               maxValue
 * -n, --num     Must be specified if you are desiring to run Part 3, otherwise
 *               it is ignored.
 *
 * @author Alex Laird
 * @author Ryan Morehart
 */
public class Project6
{
    /** The largest partition size that a task will execute for Part 3.*/
    private final int LARGEST_SIZE = 1000;
    /** Our processor ID if we are running in parallel. If the user is not running Part 2 or Part 3, this is left at -1.*/
    private int id = -1;
    /** In parallel algorithms, the number of threads that have completed their tasks.*/
    private int finishedThreads = 0;
    /** In parallel algorithms, the number of numbers that have been sorted.*/
    private int finishedCount = 0;
    /** The current number of tasks in use.*/
    private int taskCount = 0;
    /** Executor service for use in Part 3.*/
    ExecutorService pool;
    /** The number of threads to use if performing Part 2 or Part 3.*/
    private int numThreads = -1;

    /**
     * Constructs the class object with the number of threads used, if running Part 2 or Part 3.
     *
     * @param numThreads Number of threads to use.
     */
    public Project6(int numThreads)
    {
        this.numThreads = numThreads;
    }

    /**
     * Increments the variable stating the number of threads finished.
     */
    protected synchronized void threadFinished(int id)
    {
        ++finishedThreads;
    }

    /**
     * Check if the number of slave threads reporting they have finished working
     * is equal to the number of slave threads spawned.
     *
     * @return True if all spawned threads have finished, false otherwise.
     */
    private synchronized boolean waitingForThreads()
    {
        if (finishedThreads == numThreads)
        {
            return true;
        }
        return false;
    }

    /**
     * Check if the number of sorted items equals the total number of elements
     * in the array.
     *
     * @param size The number of elements total in the array.
     * @return True if all elements have been sorted, false otherwise.
     */
    private synchronized boolean waitingForCount(int size)
    {
        if (getFinishedCount () != size)
        {
            return true;
        }
        return false;
    }

    /**
     * Increment the finished counter by the given number n.
     *
     * @param n The amount to increment the finished counter by.
     */
    protected synchronized void addToFinishedCount (int n)
    {
        finishedCount += n;
    }
    
    /**
     * Retrieve the number of finished threads.
     *
     * @return The number of finished threads.
     */
    private synchronized int getFinishedCount()
    {
        return finishedCount;
    }

    /**
     * Increment the current number of tasks in use by one.
     */
    protected synchronized void incrementTaskCount()
    {
        ++taskCount;
    }

    /**
     * Retrieve the current number of tasks running.
     *
     * @return The number of tasks running.
     */
    protected synchronized int getTaskCount()
    {
        return taskCount;
    }

    /**
     * Swaps the two indeces in the array given.
     *
     * @param array The array to perform the swap on.
     * @param first Swap this index with element at second.
     * @param second Swap this index with element at first.
     */
    public void swap(int[] array,
                     int first,
                     int second)
    {
        int temp = array[first];
        array[first] = array[second];
        array[second] = temp;
    }

    /**
     * Finds the most logical point to split the array in two parts and uses
     * that point as the partition. Uses a while loop to evaluate the partition.
     *
     * @param array The array to be sorted.
     * @param low The lowest index.
     * @param high The highest index.
     * @return The index of the partitioning point.
     */
    protected int partition(int[] array,
                            int low,
                            int high)
    {
        int pivot = array[high];
        int left = low;
        int right = high - 1;

        while (left <= right)
        {
            // Increment the low pointer until you meet the pivot
            while (left <= right &&
                   array[left] <= pivot)
            {
                ++left;
            }
            // Decrement the high pointer until you meet the pivot
            while (left <= right &&
                   array[right] >= pivot)
            {
                --right;
            }

            // If the pointers have crossed, swap the items
            if (left < right)
            {
                // Swap value at left with value at right
                swap(array, left, right);
            }
        }

        // Finally, swap value at left with value at high
        swap (array, left, high);

        return left;
    }

    /**
     * Performs a standard recursive QuickSort algorithm on an array from
     * indeces high to low.
     *
     * @param array The array to be sorted.
     * @param low The lowest index.
     * @param high The highest index.
     */
    protected void sort(int[] array,
                        int low,
                        int high)
    {
        if (low < high)
        {
            // Locate the most precise partition point
            int mid = partition (array, low, high);
            // Recursively sort the lower half
            sort (array, low, mid - 1);
            // Recursively sort the upper half
            sort (array, mid + 1, high);
        }
    }

    /**
     * Continue passing partitions out to threads until the partition size is small
     * enough for us to handle ourselves, backing out of recursion.
     *
     * @param low The lowest index.
     * @param high The highest index.
     * @param array The array to be sorted.
     */
    protected void part3(int low,
                         int high,
                         int[] array)
    {
        if (high - low + 1 < LARGEST_SIZE)
        {
            // The partition is small enough, so do the work ourselves
            sort (array, low, high);
            addToFinishedCount (high - low + 1);
        }
        else
        {
            // Identify partition point
            int mid = partition (array, low, high);
            addToFinishedCount (1);

            // Launch slave task
            pool.execute (new QuickSortTask (this, getTaskCount (), mid + 1, high, array));
            incrementTaskCount ();

            // Recurse to assign the lower half to its thread
            part3(low, mid - 1, array);
        }
    }

    /**
     * Generate the array, sort it using the correct method for the given part,
     * and benchmark.
     *
     * @param part The part of the problem to perform.  Value use be 1, 2, or 3
     * @param size The size of the array to sort.
     * @param random True if numbers should be generated randomly, false if they should follow a pattern
     * @param maxValue The maximum value a randomly generated number can be
     */
    private void go(int part,
                    int size,
                    boolean random,
                    int maxValue)
    {
        // Generate array, output if length is reasonable, and declare time variables before
        // starting the time count, so as to not effect performance
        int[] array = Utility.buildArray (size, random, maxValue);
        // Copy the array to an unsorted array location for verification after the fact
        int[] unsortedArray = Arrays.copyOf (array, array.length);
        System.out.println ("::Part " + part + "::");
        System.out.println ("Array size: " + Utility.NUM_FORMAT.format (size));
        if (array.length <= 25)
        {
            System.out.print ("Initial array: ");
            Utility.printArray (array);
        }
        
        long startTime = -1;
        long endTime = -1;

        // Mark beginning time for calculation later
        startTime = System.currentTimeMillis();

        // Perform the basic, sequential QuickSort algorithm with two-pointer partition
        if (part == 1)
        {
            sort (array, 0, array.length - 1);
        }
        // Perform QuickSort using four threads, explicitely created and invoked
        else if (part == 2)
        {
            // Set this processor's ID
            id = 0;
            // Set the number of slave threads
            numThreads = 3;
            
            int low = 0;
            int high = array.length - 1;
            // Identify partition points for master and slaves
            int mid = partition (array, low, high);
            int first = partition (array, low, mid - 1);
            int second = partition (array, mid + 1, high);

            // Instantiate slave threads and pass them their partition portions
            QuickSortThread thread2 = new QuickSortThread (this, 1, first + 1, mid - 1, array);
            QuickSortThread thread3 = new QuickSortThread (this, 2, mid + 1, second - 1, array);
            QuickSortThread thread4 = new QuickSortThread (this, 3, second + 1, high, array);

            // Launch slave threads
            thread2.start ();
            thread3.start ();
            thread4.start ();
            // Current thread is the first thread, so let it do the lowest part
            sort (array, low, first - 1);

            // Wait for all threads to finish
            while (!waitingForThreads ())
            {
                continue;
            }
        }
        // Perform QuickSort on numThreads using Executor support from Java's concurrency libraries
        else if (part == 3)
        {
            // Set this processor's ID and increment task count
            id = 0;
            incrementTaskCount ();

            // Launch slave task
            pool = Executors.newFixedThreadPool (numThreads);
            pool.execute (new QuickSortTask (this, getTaskCount (), 0, array.length - 1, array));
            incrementTaskCount ();

            while (waitingForCount (array.length))
            {
                continue;
            }
            pool.shutdown();
        }

        // Mark end time and calculate total runtime
        endTime = System.currentTimeMillis();
        long totalTime = endTime - startTime;

        // Output benchmark as well as results, if length is reasonable
        if (part == 2)
        {
            System.out.println ("Threads used: 4");
        }
        else if(part == 3)
        {
            System.out.println ("Tasks used: " + numThreads);
        }
        System.out.println ("Elapsed time: " + Utility.NUM_FORMAT.format (totalTime) + "ms");
        if (array.length <= 25)
        {
            System.out.print ("Sorted array: ");
            Utility.printArray (array);
        }
        if (Utility.verifyArray (array, unsortedArray))
        {
            System.out.println ("Verified: array sorted properly");
        }
        else
        {
            System.out.println ("Unverified: array did not sort properly");
        }
        System.out.println ();
    }

    /**
     * The main method executes first in the program, parsing command-line arguments
     * and then immediately leaving static-land for the actual algorithms and
     * computations.
     *
     * @param args The command-line arguments.  "Usage: java Project6 <part> [OPTIONS]
     * <part> - Valid parts are 1, 2, or 3
     *
     * Available options:
     * -s, --size    The size of the array to generate
     * -r, --random  True indicates a random array, false indicates a seeded array
     * -m, --max     Random numbers will generated between 0 (inclusive) and maxValue
     * -n, --num     Must be specified if you are desiring to run Part 3, otherwise it is ignored.
     */
    public static void main(String[] args)
    {
        // Output string for common errors
        final String USAGE_TEXT = "Usage: java Project6 <part> [OPTIONS]\n"
        + "<part> - Valid parts are 1, 2, or 3\n\n"
        + "Available options:\n"
        + "-s, --size      The size of the array to generate\n"
        + "-r, --random    True indicates a random array, false indicates a seeded array\n"
        + "-m, --max       Random numbers will generated between 0 (inclusive) and maxValue\n"
        + "-n, --num       Must be specified if you are desiring to run Part 3, otherwise it is ignored.";
        // The part of the problem to perform.  Value use be 1, 2, or 3
        int part = -1;
        // The size of the array to sort.*/
        int size = 10;
        // True if numbers should be generated randomly, false if they should follow a pattern
        boolean random = false;
        // The maximum value a randomly generated number can be
        int maxValue = 10;
        // The number of threads to use if performing Part 3
        int numThreads = -1;
        
        // Parse through arguments and set their respective variables
        if (args.length > 0)
        {
            part = Integer.parseInt (args[0]);

            try
            {
                for (int i = 1; i < args.length; i += 2)
                {
                    if (args[i].equals ("-s"))
                    {
                        size = Integer.parseInt (args[i + 1]);
                    }
                    else if(args[i].equals ("-r"))
                    {
                        if (args[i + 1].equals ("true"))
                        {
                            random = true;
                        }
                        else if (!args[i + 1].equals ("false"))
                        {
                            int intRand = Integer.parseInt (args[i + 1]);
                            if (intRand == 1)
                            {
                                random = true;
                            }
                            else if (intRand != 0)
                            {
                                // Since the given random value was not valid at this point, just break the given part so the program termiantes
                                part = -1;
                            }
                        }
                    }
                    else if(args[i].equals("-m"))
                    {
                        maxValue = Integer.parseInt(args[i + 1]);
                    }
                    else if(args[i].equals("-n"))
                    {
                        numThreads = Integer.parseInt(args[i + 1]);
                    }
                }
            }
            catch (NumberFormatException ex)
            {
                System.out.println (USAGE_TEXT);
                System.exit (2);
            }

            // Make sure the given part number was valid
            if (part > 3 || part < 1)
            {
                System.out.println (USAGE_TEXT);
                System.exit (3);
            }

            // If we are doing Part 3 and the number of desired threads was not given, we cannot continue
            if (part == 3 && numThreads == -1)
            {
                System.out.println (USAGE_TEXT);
                System.exit (4);
            }
        }
        else
        {
            System.out.println (USAGE_TEXT);
            System.exit (1);
        }

        // Get us out of static-land!
        Project6 proj6 = new Project6 (numThreads);
        proj6.go (part, size, random, maxValue);
    }
}

class QuickSortTask implements Runnable
{
    /** The back-reference to the class containing the sorting routine.*/
    Project6 proj6;
    /** The ID of this task.*/
    int id;
    /** The lowest index this task goes in the array.*/
    int low;
    /** The highest index this task goes in the array.*/
    int high;
    /** The array to be sorted.*/
    int[] array;

    /**
     * Construct a new task, giving it a class reference containing the sorting
     * routine as well as the array to be sorted.
     *
     * @param proj6 Pass the reference to the class containing necessary sorting routine.
     * @param id The ID of this task.
     * @param low The lowest index this task goes in the array.
     * @param high The highest index this task goes in the array.
     * @param array The array to be sorted.
     */
    public QuickSortTask (Project6 proj6,
                          int id,
                          int low,
                          int high,
                          int[] array)
    {
        this.proj6 = proj6;
        this.id = id;
        this.low = low;
        this.high = high;
        this.array = array;
    }

    /**
     * Instantiates the task and performs the sort on the given array for the
     * specified portions.
     */
    @Override
    public void run()
    {
        proj6.part3 (low, high, array);
    }
}


/**
 * This class contains common, simple helper functions that are globally
 * available to any class that needs them.
 *
 * @author Alex Laird
 * @author Ryan Morehart
 */
 class Utility
{
    /** The number formatter for pretty output.*/
    public static final NumberFormat NUM_FORMAT = new DecimalFormat ("###,###");
    
    /**
     * Builds an array of given size with random values (if random is true) between
     * 0 (inclusive) and MAX_VALUE.  If random is set to false, values are seeded to
     * the indeces of the array.
     * 
     * @param size The size to build the array.
     * @param random True if values should be random, false if values should be seeded.
     * @param MAX_VALUE The maximum value of a randomly generated number.
     * @return The newly built array.
     */
    public static int[] buildArray (int size,
                                    boolean random,
                                    final int MAX_VALUE)
    {
        int[] array = new int[size];
        Random randomizer = new Random ();

        // Loop through and set all array values
        for (int i = 0; i < size; ++i)
        {
            // If random, set value between 0 (inclusive) and MAX_VALUE
            if (random)
            {
                array[i] = randomizer.nextInt(MAX_VALUE);
            }
            // Not random, so set value to the index of the array
            else
            {
                array[i] = i;
            }
        }

        return array;
    }

    /**
     * Verify that the two arrays are equal by sorting the unsorted array, using
     * verified Java sorting libraries, and comparing the two arrays.
     *
     * @param sortedArray The sorted array.
     * @param unsortedArray The unsorted array to be sorted and compared to the sorted array.
     * @return True if the arrays are equal after sorting using Java sorting libraries, false if there was an inconsistency.
     */
    public static boolean verifyArray(int[] sortedArray,
                                      int[] unsortedArray)
    {
        Arrays.sort (unsortedArray);
        for (int i = 0; i < sortedArray.length ;++i)
        {
            if (sortedArray[i] != unsortedArray[i])
            {
                return false;
            }
        }
        return true;
    }

    /**
     * Print the given array.
     *
     * @param array The array to be printed.
     */
    public static void printArray(int[] array)
    {
        for (int i = 0; i < array.length; ++i)
        {
            System.out.print (array[i]);
            if (i < array.length - 1)
            {
                System.out.print (", ");
            }
        }
        System.out.println ();
    }
}

 /**
  * A thread that will sort a set array upon execution.
  *
  * @author Alex Laird
  * @author Ryan Morehart
  */
  class QuickSortThread extends Thread
 {
     /** The back-reference to the class containing the sorting routine.*/
     Project6 proj6;
     /** The ID of this thread.*/
     int id;
     /** The lowest index this thread goes in the array.*/
     int low;
     /** The highest index this thread goes in the array.*/
     int high;
     /** The array to be sorted.*/
     int[] array;

     /**
      * Construct a new thread, giving it a class reference containing the sorting
      * routine as well as the array to be sorted.
      * 
      * @param proj6 Pass the reference to the class containing necessary sorting routine.
      * @param id The ID of this thread.
      * @param low The lowest index this thread goes in the array.
      * @param high The highest index this thread goes in the array.
      * @param array The array to be sorted.
      */
     public QuickSortThread (Project6 proj6,
                             int id,
                             int low,
                             int high,
                             int[] array)
     {
         this.proj6 = proj6;
         this.id = id;
         this.low = low;
         this.high = high;
         this.array = array;
     }

     /**
      * Instantiates the thread and performs the sort on the given array for the
      * specified portions.
      */
     @Override
     public void run()
     {
         proj6.sort (array, low, high);
         proj6.threadFinished (id);
     }
 }

   
    
    
    
    
  








Related examples in the same category

1.Linear search
2.Animation for quick sort
3.Quick Sort Implementation with median-of-three partitioning and cutoff for small arrays
4.Simple Sort DemoSimple Sort Demo
5.A simple applet class to demonstrate a sort algorithm
6.Sorting an array of StringsSorting an array of Strings
7.Simple version of quick sortSimple version of quick sort
8.Combine Quick Sort Insertion SortCombine Quick Sort Insertion Sort
9.Quick sort with median-of-three partitioningQuick sort with median-of-three partitioning
10.Fast Quick Sort
11.Selection sortSelection sort
12.Insert Sort for objectsInsert Sort for objects
13.Insert sortInsert sort
14.Bubble sortBubble sort
15.Merge sortMerge sort
16.Fast Merge Sort
17.Binary SearchBinary Search
18.Shell sortShell sort
19.Recursive Binary Search Implementation in Java
20.Topological sortingTopological sorting
21.Heap sortHeap sort
22.Sort NumbersSort Numbers
23.A quick sort demonstration algorithmA quick sort demonstration algorithm
24.Performing Binary Search on Java byte Array Example
25.Performing Binary Search on Java char Array Example
26.Performing Binary Search on Java double Array Example
27.Performing Binary Search on Java float Array Example
28.Performing Binary Search on Java int Array Example
29.Performing Binary Search on Java long Array Example
30.Performing Binary Search on Java short Array
31.Sort items of an array
32.Sort an array of objects
33.Sort a String array
34.Sort string array with Collator
35.Binary search routines
36.FastQ Sorts the [l,r] partition (inclusive) of the specfied array of Rows, using the comparator.FastQ Sorts the [l,r] partition (inclusive) of the specfied array of Rows, using the comparator.
37.A binary search implementation.
38.Handles QuickSort and all of its methods.
39.A quick sort algorithm to sort Vectors or arrays. Provides sort and binary search capabilities.A quick sort algorithm to sort Vectors or arrays. Provides sort and binary search capabilities.
40.Returns an array of indices indicating the order the data should be sorted in.