/* 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); }
/* 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(); } }
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; }
/* 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); }