/* Sorts an array using Selection sort algorithm.
         * Prints updates if printUpdates is true.
         * Doesn't redundantly swap the last remaining element with itself.
         * Time complexity: Worst = n^2, Best = n^2, Average = n^2.
         */
        public static int[] Sort(int[] array, bool printUpdates)
        {
            ulong comparisons = 0;
            ulong swaps       = 0;
            int   n           = array.Length;

            // The leftmost element will be skipped at each successive loop, since we know it's now sorted.
            // Also, the condition is ( < n-1 ) instead of ( < n ) to avoid swapping the last element with itself.
            for (int firstUnsortedIndex = 0; firstUnsortedIndex < n - 1; firstUnsortedIndex++)
            {
                if (printUpdates)
                {
                    Console.WriteLine("Go through unsorted section to find minimum:");
                }
                // Assume the first unsorted element is the smallest, store its index
                int min        = array[firstUnsortedIndex];
                int indexOfMin = firstUnsortedIndex;
                // Iterate through the unsorted array and find the smallest element
                for (int currentIndex = firstUnsortedIndex + 1; currentIndex < n; currentIndex++)
                {
                    // Since the next line will compare elements, add 1 to comparisons
                    comparisons++;
                    if (printUpdates)
                    {
                        Console.WriteLine("^ Compare " + min.ToString().PadLeft(2) +
                                          " with " + array[currentIndex].ToString().PadLeft(2));
                    }
                    if (array[currentIndex] < min)
                    {
                        min        = array[currentIndex];
                        indexOfMin = currentIndex;
                    }
                }
                // Swap the smallest element with the first unsorted element. Count 1 more swap.
                ArrayOperations.Swap(array, indexOfMin, firstUnsortedIndex);
                swaps++;

                // Since a swap was made, print array in current state and say what was swapped
                if (printUpdates)
                {
                    Console.WriteLine("Minimum = {0}, swap with first unsorted element:", min);
                    string message = "swapped " + array[indexOfMin].ToString().PadLeft(2) +
                                     " with " + array[firstUnsortedIndex].ToString().PadLeft(2);
                    ArrayOperations.Print(array, message);
                }
            }

            // Print number of comparisons and swaps that were performed
            if (printUpdates)
            {
                Console.WriteLine("Since there's only one element left, it must be in the right place and we're done!");
                Console.WriteLine("\nNumber of comparisons: " + comparisons +
                                  "\nNumber of swaps: " + swaps);
            }

            CountAndDisplay.totalComparisonsSelection += comparisons;
            CountAndDisplay.totalSwapsSelection       += swaps;
            return(array);
        }
예제 #2
0
        /* Returns the pivot for Quicksort's Partition method.
         * Choice of three methods of finding the pivot: end, random, and median-of-three
         * Choose by setting the value of 'pivotMethod' a few lines down.
         *
         * A note on median-of-three from Wikipedia:
         * "Although this approach optimizes quite well, it is typically outperformed in practice
         * by instead choosing random pivots, which has average linear time for selection and
         * average log-linear time for sorting, and avoids the overhead of computing the pivot."
         */
        public static int GetPivot(int[] array, int start, int end)
        {
            int pivotMethod = 2;    //Set here: 0 = end, 1 = random, 2 = median-of-three

            // Method 1: Pivot = end
            // This gives Quicksort a running time O(n^2) in the worst case (already sorted)
            if (pivotMethod == 0)
            {
                return(end);
            }

            // Method 2: Pivot = random
            else if (pivotMethod == 1)
            {
                // Pivot is the element at a random index in this part of the array
                Random rnd = new Random();
                int    i   = rnd.Next(start, end + 1);

                // Swap the pivot with the end (end is now pivot)
                ArrayOperations.Swap(array, i, end);
                CountAndDisplay.totalSwapsQuick++;

                return(end);
            }

            // Method 3: Pivot = 'median of three', change the array as required
            else
            {
                int mid = (start + end) / 2;

                // Ensure start < mid < end
                if (array[start] > array[end])
                {
                    ArrayOperations.Swap(array, start, end);
                    CountAndDisplay.totalSwapsQuick++;
                }
                if (array[start] > array[mid])
                {
                    ArrayOperations.Swap(array, start, mid);
                    CountAndDisplay.totalSwapsQuick++;
                }
                if (array[mid] > array[end])
                {
                    ArrayOperations.Swap(array, mid, end);
                    CountAndDisplay.totalSwapsQuick++;
                }

                // Swap mid and end (end is now pivot)
                ArrayOperations.Swap(array, end, mid);
                CountAndDisplay.totalSwapsQuick++;

                return(end);
            }
        }
예제 #3
0
        /* Calls all sorting algorithms and prints additional information to specify which sort is which */
        private static void CallAllSorts(int[] array, bool printUpdates)
        {
            // Copy each array (since they're arrays of ints, shallow copy is enough)
            int[] array1 = (int[])array.Clone();
            int[] array2 = (int[])array.Clone();
            int[] array3 = (int[])array.Clone();
            int[] array4 = (int[])array.Clone();

            if (printUpdates)
            {
                Console.WriteLine("\nBubble sort:" +
                                  "\n************");
                ArrayOperations.Print(array, "initial array");
            }
            Bubble.Sort(array, printUpdates);

            if (printUpdates)
            {
                Console.WriteLine("\nSelection sort:" +
                                  "\n***************");
                ArrayOperations.Print(array1, "initial array");
            }
            Selection.Sort(array1, printUpdates);

            if (printUpdates)
            {
                Console.WriteLine("\nInsertion sort:" +
                                  "\n***************");
                ArrayOperations.Print(array2, "initial array");
            }
            Insertion.Sort(array2, printUpdates);

            if (printUpdates)
            {
                Console.WriteLine("\nQuick sort:" +
                                  "\n***********");
                ArrayOperations.Print(array3, "initial array");
            }
            Quick.Sort(array3, 0, array3.Length - 1, printUpdates);

            if (printUpdates)
            {
                Console.WriteLine("\nMerge sort:" +
                                  "\n***********");
                ArrayOperations.Print(array4, "initial array");
            }
            Merge.Sort(array4, printUpdates);

            if (printUpdates)
            {
                Console.WriteLine();
            }
        }
예제 #4
0
        public static void Init(string sortingAlgorithm, string orderOfInitialArray, ulong numberOfSorts, int lengthOfArray, bool printUpdates)
        {
            /* Initialise specified number of arrays of ints
             * Pass each one to Bubble||Selection||Insertion||Quick sort
             * Count total number of comparisons/swaps/shuffles/insertions as required
             */
            for (int i = 0; i < (int)numberOfSorts; i++)
            {
                if (numberOfSorts > 1 && printUpdates == true)
                {
                    Console.WriteLine("\n\nRound {0}:\n", (i + 1));
                }

                // Create array
                int[] array = ArrayOperations.Make(lengthOfArray, orderOfInitialArray);

                if (printUpdates && sortingAlgorithm != A)
                {
                    ArrayOperations.Print(array, "initial array");
                }

                switch (sortingAlgorithm)
                {
                case B:
                    Bubble.Sort(array, printUpdates);
                    break;

                case S:
                    Selection.Sort(array, printUpdates);
                    break;

                case I:
                    Insertion.Sort(array, printUpdates);
                    break;

                case Q:
                    Quick.Sort(array, 0, array.Length - 1, printUpdates);
                    break;

                case M:
                    Merge.Sort(array, printUpdates);
                    break;

                default:
                    CallAllSorts(array, printUpdates);
                    break;
                }
            }
        }
        // Merges two sorted arrays into one sorted array
        public static void MergeArrays(int[] array, int[] leftArray, int[] rightArray, bool printUpdates)
        {
            ulong comparisons = 0;
            ulong swaps       = 0;

            int leftCount  = leftArray.Length;
            int rightCount = rightArray.Length;

            int l = 0; // index of left sub-array
            int r = 0; // index of right sub-array
            int m = 0; // index of merged array


            // Copy the next value in left and right sub-arrays to the main array
            while (l < leftCount && r < rightCount)
            {
                comparisons++;
                swaps++;
                if (leftArray[l] < rightArray[r])
                {
                    array[m++] = leftArray[l++];
                }
                else
                {
                    array[m++] = rightArray[r++];
                }
            }
            // If end of right subarray reached first, copy remaining elements from left subarray
            while (l < leftCount)
            {
                swaps++;
                array[m++] = leftArray[l++];
            }
            // If end of left subarray reached first, copy remaining elements from right subarray
            while (r < rightCount)
            {
                swaps++;
                array[m++] = rightArray[r++];
            }

            if (printUpdates)
            {
                ArrayOperations.Print(array, "<- After a completed Merge of two sub-arrays");
            }

            CountAndDisplay.totalComparisonsMerge += comparisons;
            CountAndDisplay.totalSwapsMerge       += swaps;
        }
예제 #6
0
        /* Sets pivot to some element in the given array, and partitionIndex to the first.
         * Iterates through each element and compares against the pivot.
         * If it's less than or equal to the pivot, swap it with partitionIndex++.
         * If it's greater than pivot, leave it alone.
         * Finally, swap the pivot with the partitionIndex.
         * Now, all elements <= pivot are on its left, and elements > pivot are on the right.
         */
        public static int Partition(int[] array, int start, int end, bool printUpdates)
        {
            ulong comparisons = 0;
            ulong swaps       = 0;

            // Set pivot (one of three methods, see GetPivot method)
            int pivotIndex = GetPivot(array, start, end);
            int pivot      = array[pivotIndex];
            // Set partitionIndex to start
            int partitionIndex = start;

            if (printUpdates)
            {
                Console.WriteLine("Pivot is {0}, move < elements to left and >= to right", pivot);
            }

            // Iterate from start to end - 1 (because end is always the pivot)
            for (int i = start; i < end; i++)
            {
                // Compare each element to the pivot
                comparisons++;
                if (array[i] < pivot)
                {
                    // If it's < pivot, swap to left of partition
                    ArrayOperations.Swap(array, i, partitionIndex);
                    partitionIndex++;
                    swaps++;
                }
            }

            // Move the pivot to the partition. Now, elements left are <= pivot, right are > pivot
            ArrayOperations.Swap(array, end, partitionIndex);
            swaps++;

            CountAndDisplay.totalComparisonsQuick += comparisons;
            CountAndDisplay.totalSwapsQuick       += swaps;

            if (printUpdates)
            {
                string message = "Pivot was " + pivot.ToString().PadLeft(2) + ", moved to index " + partitionIndex.ToString().PadLeft(2);
                ArrayOperations.Print(array, message);
            }
            return(partitionIndex);
        }
        /* Sorts an array using Bubble sort algorithm.
         * Prints updates if printUpdates is true.
         * Optimised: will only loop once through an array once after it's sorted,
         * and distinguishes between 'sorted' and 'unsorted' parts.
         * Time complexity: Worst = n^2, Best = n, Average = n^2.
         */
        public static int[] Sort(int[] array, bool printUpdates)
        {
            ulong comparisons = 0;
            ulong swaps       = 0;
            // Get (length - 1) because we compare with (j + 1)
            int  n       = array.Length - 1;
            bool swapped = false;

            /* Loop through the array, checking that each element is smaller than the next.
             * If not, swap those two elements and mark 'swapped' to true.
             * Stop looping when the whole array has been checked without making a swap.
             */
            do
            {
                swapped = false;
                for (int j = 0; j < n; j++)
                {
                    // Since the next line will compare elements, add 1 to comparisons
                    comparisons++;
                    if (printUpdates)
                    {
                        Console.Write("^ Compare " + array[j].ToString().PadLeft(2) +
                                      " with " + array[j + 1].ToString().PadLeft(2));
                    }
                    if ((array[j] > array[j + 1]))
                    {
                        // Swap them, set 'swapped' to true, count 1 more swap
                        ArrayOperations.Swap(array, j, j + 1);
                        swapped = true;
                        swaps++;

                        // Since a swap was made, print array in current state and say what was swapped
                        if (printUpdates)
                        {
                            Console.WriteLine(", it's bigger so swap:");
                            string message = "swapped " + array[j + 1].ToString().PadLeft(2) +
                                             " with " + array[j].ToString().PadLeft(2);
                            ArrayOperations.Print(array, message);
                        }
                    }
                    else if (printUpdates)
                    {
                        Console.WriteLine(", it's not bigger so don't swap");
                    }
                }
                // After each loop, we know the biggest element must be sorted
                // So, it can be ignored on the next pass
                n--;
            } while (swapped);

            // Print number of comparisons and swaps that were performed
            if (printUpdates)
            {
                Console.WriteLine("Since no swaps were made this pass, we're done!");
                Console.WriteLine("\nNumber of comparisons: " + comparisons +
                                  "\nNumber of swaps: " + swaps);
            }

            CountAndDisplay.totalComparisonsBubble += comparisons;
            CountAndDisplay.totalSwapsBubble       += swaps;
            return(array);
        }
        /* Sorts an array using Insertion sort algorithm.
         * Prints updates if printUpdates is true.
         * At the end, prints a summary of the number of comparisons, shuffles, and insertions.
         * Time complexity: Worst = n^2, Best = n, Average = n^2.
         */
        public static int[] Sort(int[] array, bool printUpdates)
        {
            // Since elements aren't directly swapped, it doesn't make sense to count swaps like the other algorithms.
            // Instead, we count shuffles (when an element moves up one index)
            // and insertions (where the currentElement is inserted into its correct index for that pass)
            ulong comparisons = 0,
                  shuffles    = 0,
                  insertions  = 0;
            int n             = array.Length;

            // We begin at index 1 since we will compare with the element before it
            for (int i = 1; i < n; i++)
            {
                // Store the current element's value and index
                int currentElement = array[i],
                    j = i;

                // The next line will compare two elements, so add 1 to comparisons
                comparisons++;
                if (printUpdates && j > 0)
                {
                    Console.Write("^ Compare " + currentElement.ToString().PadLeft(2) +
                                  " with " + array[j - 1].ToString().PadLeft(2));
                }
                bool endReached = false;
                // Shuffle the required number of previous elements, to 'make room' for the currentElement
                while (j > 0 && array[j - 1] > currentElement)
                {
                    array[j] = array[j - 1];
                    j--;
                    // An element was just moved by one index, so add 1 to shuffles
                    shuffles++;

                    if (printUpdates)
                    {
                        Console.WriteLine(", {0} is bigger so we shuffle it one place up to index {1}", array[j], j);
                    }

                    // The while condition will now compare two elements again (unless j is now 0), so add 1 to comparisons
                    if (j != 0)
                    {
                        comparisons++;
                        if (printUpdates)
                        {
                            Console.Write("^ Compare " + currentElement.ToString().PadLeft(2) +
                                          " with " + array[j - 1].ToString().PadLeft(2));
                        }
                    }
                    else if (printUpdates)
                    {
                        endReached = true;
                        Console.WriteLine("We've reached the first index so insert {0} here:", currentElement.ToString().PadLeft(2));
                    }
                }

                if (printUpdates && !endReached)
                {
                    Console.WriteLine(", it's not smaller so we insert {0} here:", currentElement.ToString().PadLeft(2));
                }

                // Insert the currentElement in its correct index for this pass, and add 1 to insertions
                array[j] = currentElement;
                insertions++;

                // Since an insertion was made, print array in current state and say what was inserted
                if (printUpdates)
                {
                    string message = "inserted " + currentElement.ToString().PadLeft(2) +
                                     " to index " + j.ToString().PadLeft(2);
                    ArrayOperations.Print(array, message);
                }
            }

            // Print number of comparisons, shuffles and insertions that were performed
            if (printUpdates)
            {
                Console.WriteLine("Since that was the last element, we're done!");
                Console.WriteLine("\nNumber of comparisons: " + comparisons +
                                  "\nNumber of shuffles: " + shuffles +
                                  "\nNumber of insertions: " + insertions);
            }

            CountAndDisplay.totalComparisonsInsertion += comparisons;
            CountAndDisplay.totalShuffles             += shuffles;
            CountAndDisplay.totalInsertions           += insertions;
            return(array);
        }