diff --git a/README.md b/README.md index 7643575..487a026 100644 --- a/README.md +++ b/README.md @@ -9,280 +9,19 @@ Written in python by Thomas Gibson. | [2. Sorting Algorithms](#sorting-algorithms) | | [3. Adding a new Search Algorithm](#adding-a-new-search-algorithm) | | [4. Adding a new Sorting Algorithm](#adding-a-new-sorting-algorithm) | ---- - -## Searching Algorithms: - -Below is a table containing the searching algorithms this project visualises.
-The links in the table direct to a information about the algorithm and its implementation steps. - -| Algorithm | -| --------- | -| [Linear Search](#linear-search) | -| [Binary Search](#binary-search) | -| [Jump Search](#jump-search) | -| [Tenary Search](#tenary-search) | -| [Fibonacci Search](#fibonacci-search) | - ---- -### Linear Search: ---- -Algorithm Steps:
-1. Starting at the beginning of the array -2. Compare current value to the target -3. If the value is equal to the target then return 1 -4. If the value is not equal to the target then go to the next element -5. Repeat steps 2 - 4 until the end of array is reached -6. If the end of the array has been reached and target has not been found, return 0 - -Time Complexity: O(n)
-Space Complexity: O(1) - ---- -### Binary Search: ---- -Algorithm steps: - -1. Intialise a variable called low with a value of 0 -2. Intialise a variable called high that is equal to the length of the array minus one -3. While low is less than or equal to high -4. Initialise a varible called mid, it's value is calculated by [the formula](#mid-formula) -5. If the value at index mid is equal to the target, return 1 -6. If the value at index mid is greater than the target, set low to mid plus one -7. If the value at index mid is less than the target, set high to mid minus one -8. Repeat steps 3 - 7 until low is greater than high -9. If the loop terminates, return 0 - -Time complexity: O(log n)
-Space Complexity: O(1) - -#### mid formula: - -$mid = {(low+high) \div 2}$ - ---- -### Jump Search: ---- -Algorithm Steps: - -1. Initialize a variable called step and set it's value to $\sqrt{n}$ (where n is the length of the array) -2. Create a variable called prev and set it's value to 0 -3. While step is less than n, set prev to the value of step and then increment step by $\sqrt{n}$.
-If prev is greater than or equal to n, return false. Else if the value at index step is greater than target, break loop. -4. Initialize a loop starting at the value of prev until prev + $\sqrt{n}$ -5. If the current index is equal to the target, return 1 -6. If the current index is greater than the target, return 0 -7. Else repeat steps 5 - 6 until reached index corresponding to prev + $\sqrt{n}$ - -Time Complexity: O($\sqrt{n}$)
-Space Complexity: O(1) - ---- -### Tenary Search: ---- -Algorithm Steps: - -1. Intialise a variable called left with a value of 0 -2. Intialise a variable called right that is equal to the length of the array minus one -3. While left is less than or equal to right -4. Initialise a varible called mid1, calculate it's value using [the formula](#mid1-formula) -5. Initialise a varible called mid2, calculate it's value using [the formula](#mid2-formula) -6. If the value at index mid1 or mid2 is equal to the target, return 1 -7. If the value at index mid1 is less than the target, set right to mid1 - 1 -8. If the value at index mid2 is greater than the target, set left to mid2 + 1 -9. Else, set left to mid1 + 1 and set right to mid2 - 1 -10. Repeat steps 3 - 9 -11. If the loop terminates, return 0 - -Time Complexity: O(log3n)
-Space Complexity: O(1) - -#### mid1 formula: - -$mid1 = {left + (right - left) \div 3}$ - -#### mid2 formula: - -$mid2 = {right - (right - left) \div 3}$ - ---- -### Fibonacci Search: ---- -Algorithm Steps: - -1. Calculate the largest Fibonacci number greater than or equal to the size of the array, store it in a variable called fibN -2. Calculate the Fibonacci number before fibN, store it in a variable called fibNMin1 -3. Calculate the Fibonacci number before fibNMin1, store it in a variable called fibNMin2 -4. Initialise a variable called offset, set it to -1 -5. Initialise a variable called n, set it to the length of the array -6. While fibN is greater than 1 -7. Initialise a variable called index, it's value is given by [the formula](#index-formula) -8. If the element at index is less than the target, move all the Fibonacci numbers, two Fibonacci numbers down. set offset to be equal to index -9. Else if the element at index is greater than the target, move all the Fibonacci numbers, one Fibonacci number down -10. Else, the target has been found, return 1 -11. Repeat steps 6 to 10 -12. If fibMin1 is greater than 0 and the last element in the array is the target, return 1 -13. Else, return 0 - -Time Complexity: O(log n)
-Space Complexity: O(1) - -#### index formula: - -$index = {\min(offset + fibNMin2, n - 1)}$ - ---- -### Exponential Search: ---- -Algorithm Steps: - -1. If the first element in the array is the target, return 1 -2. Initialise a variable called i, set it to 1 -3. Initialise a variable called n, set it to the length of the array -4. While i is less than n and the element at index i is less than or equal to the target -5. Double the value of i -6. Repeat Steps 5 - 6 -7. Perform a [binary search](#binary-search), the initialise values for [low](#initial-low-value) and [high](#initial-high-value) are given below - -Time Complexity: O(log n)
-Space Complexity: O(1) - -#### Starting low value: - -$low = i \div 2$ +| [5. The Algorithm class](#algorithm-class) | +| [6. The DataModel class](#datamodel-class) | -#### Starting high value: -$high = \min(i, n - 1)$ +## Searching Algorithms ---- -### Interpolation Search: ---- -Algorithm Steps: - -1. Initialise a variable called low and set it to 0 -2. Initialise a variable called high and set it to the length of the array - 1 -3. While low is less than or equal to high AND target is greater than or equal to the value at index low AND target is less than or equal to the value at index high -4. Initialise a value called pos and calculate it's value using [the formula](#pos-formula) -5. If the value at index pos is equal to the target, return 1 -6. If the value at index pos is greater than the target, set high to pos - 1 -7. If the value at index pos is less than the target, set low to pos + 1 -8. Repeat steps 3 - 7 -9. If the loop terminates and the target is not found, return 0 - -Time Complexity: O(log (log n))
-Space Complexity: O(1) - -#### pos formula: - -$$pos = {low+{(target-array[low])\times(high - low)\over(array[high]-array[low])}}$$ - ---- - -## Sorting Algorithms: - -Below is a table containing the sorting algorithms this project visualises.
-The links in the table direct to a information about the algorithm and its implementation steps. - -| Algorithm | -| --------- | -| [Bubble Sort](#bubble-sort) | -| [Merge Sort](#merge-sort) | -| [Bogo Sort](#bogo-sort) | +A full list of implmeneted Searching algorithms can be found [here](./algorithms/SEARCHING.md) +## Sorting Algorithms ---- -### Bubble Sort: ---- -Algorithm steps: - -1. Loop through the array from left to right -2. At the beginning of each iteration set a boolean flag to False -3. In a nested loop, traverse from the beginning of the array to the end of the unsorted array using [this formula](#index-of-last-sorted-element-formula) -4. Compare the current element to the element adjacent to it -5. If the current element is greater than the adjacent elment, swap them and set the boolean flag to True -6. When the nested loop has terminated check the value of the boolean flag -7. If the boolean flag is True, continue for another iteration -8. If the boolean flag is False, the array is sorted and the algorithm should terminate. - -Time Complexity: O(n2)
-Space Complexity: O(1) - -#### End of unsorted array formula: - -$$ index = n - i - 1$$ - -n -> length of the array
-i -> index of current element - ---- -### Merge Sort: ---- -Algorithm Steps: - -1. Divide the array into sub-arrays of size one. (Arrays of size one are considered sorted) -2. Compare the elements in each of the sub-arrays, inserting them in numerical order into a new sub-array -3. Repeat step 2 until all the sub-arrays have been merged leaving only one sorted array -Time Complexity: O(n log n)
-Space Complexity: O(n) +A full list of implmeneted Sorting algorithms can be found [here](./algorithms/SORTING.md) ---- -### Bogo Sort: ---- - -Algorithm Steps: - -1. Randomly shuffle array -2. If array is sorted, stop. -3. If array is not sorted repeat step 1. - -Time Complexity: O((n + 1)!)
-Space Complexity: O(1) - ---- -### Quick Sort: ---- - -Algorithm Steps: - -1. Initialise a variable called low and assign it the value 0 -2. Initialise a variavle called high and assign it the length of the array minus one -3. Select pivot using median of three -4. All elements less than the pivot must be placed to the left of the pivot -5. All elements greater than the pivot must be places to the right of the pivot -6. Two new pivots need to be selected to sort the separate halves of the array -7. The first pivot should be in the range, low to index of current pivot - 1 -8. The second pivot should be in the range, index of current pivot + 1 to end -9. Repeat steps 3 - 8 until low is greater than pivot index - 1 and pivot index + 1 is greater than end - -Time Complexity: O(log n)
-Time Complexity: O(n2) (If the pivot is chosen poorly)
-Space Complexity: O(1) - -#### Median of three - -- Get the elements at low, high and (low + high) / 2 -- Place the element in an array and sort -- The pivot is the middle value (element in index 1) - ---- -### Selection Sort: ---- - -Algorithm Steps: - -1. Iterate through the array -2. Set a variable called minIdx to the current index -3. In a nested loop from the current index plus one to the end of the array -4. Find the index of the smallest element and store it in minIdx -5. Shift all elements between the current index and the smallest element index one place right -6. Place the smallest element into the current index - -Time Complexity: O(n2)
-Space Complexity: O(1) - ---- ## Adding a new Search Algorithm New search algorithms can be added if they meet these requirements: @@ -340,7 +79,7 @@ def __init__(self, dataModel): --- -### Algorithm class: +## Algorithm class: The algorithm class is a wrapper for some of the [DataModel](#datamodel-class) class functions.
These functions are needed to interact with the visualizer properly.
@@ -364,7 +103,7 @@ The methods in DataModel can still be called directly (not recommended). | delay() | None | None | Pauses the execution of the program using time.sleep(). | -### DataModel class: +## DataModel class: Useful functions, most are wrapped by the [Algorithm](#algorithm-class) class.
The functions can still be called directly, if an attribute containing the DataModel class is created (not recommended). diff --git a/algorithms/SEARCHING.md b/algorithms/SEARCHING.md new file mode 100644 index 0000000..7be879f --- /dev/null +++ b/algorithms/SEARCHING.md @@ -0,0 +1,171 @@ +## Searching Algorithms: + +Below is a table containing the searching algorithms this project visualises.
+The links in the table direct to a information about the algorithm and its implementation steps. + +| Algorithm | +| --------------------------------------------- | +| [Binary Search](#binary-search) | +| [Exponential Search](#exponential-search) | +| [Fibonacci Search](#fibonacci-search) | +| [Interpolation Search](#interpolation-search) | +| [Jump Search](#jump-search) | +| [Linear Search](#linear-search) | +| [Tenary Search](#tenary-search) | + +--- +### Binary Search: + +Algorithm steps: + +1. Intialise a variable called low with a value of 0 +2. Intialise a variable called high that is equal to the length of the array minus one +3. While low is less than or equal to high +4. Initialise a varible called mid, it's value is calculated by [the formula](#mid-formula) +5. If the value at index mid is equal to the target, return 1 +6. If the value at index mid is greater than the target, set low to mid plus one +7. If the value at index mid is less than the target, set high to mid minus one +8. Repeat steps 3 - 7 until low is greater than high +9. If the loop terminates, return 0 + +Time complexity: O(log n)
+Space Complexity: O(1) + +#### mid formula: + +$mid = {(low+high) \div 2}$ + +--- +### Exponential Search: + +Algorithm Steps: + +1. If the first element in the array is the target, return 1 +2. Initialise a variable called i, set it to 1 +3. Initialise a variable called n, set it to the length of the array +4. While i is less than n and the element at index i is less than or equal to the target +5. Double the value of i +6. Repeat Steps 5 - 6 +7. Perform a [binary search](#binary-search), the initialise values for [low](#initial-low-value) and [high](#initial-high-value) are given below + +Time Complexity: O(log n)
+Space Complexity: O(1) + +#### Starting low value: + +$low = i \div 2$ + +#### Starting high value: + +$high = \min(i, n - 1)$ + +--- +### Fibonacci Search: + +Algorithm Steps: + +1. Calculate the largest Fibonacci number greater than or equal to the size of the array, store it in a variable called fibN +2. Calculate the Fibonacci number before fibN, store it in a variable called fibNMin1 +3. Calculate the Fibonacci number before fibNMin1, store it in a variable called fibNMin2 +4. Initialise a variable called offset, set it to -1 +5. Initialise a variable called n, set it to the length of the array +6. While fibN is greater than 1 +7. Initialise a variable called index, it's value is given by [the formula](#index-formula) +8. If the element at index is less than the target, move all the Fibonacci numbers, two Fibonacci numbers down. set offset to be equal to index +9. Else if the element at index is greater than the target, move all the Fibonacci numbers, one Fibonacci number down +10. Else, the target has been found, return 1 +11. Repeat steps 6 to 10 +12. If fibMin1 is greater than 0 and the last element in the array is the target, return 1 +13. Else, return 0 + +Time Complexity: O(log n)
+Space Complexity: O(1) + +#### index formula: + +$index = {\min(offset + fibNMin2, n - 1)}$ + +--- +### Interpolation Search: + +Algorithm Steps: + +1. Initialise a variable called low and set it to 0 +2. Initialise a variable called high and set it to the length of the array - 1 +3. While low is less than or equal to high AND target is greater than or equal to the value at index low AND target is less than or equal to the value at index high +4. Initialise a value called pos and calculate it's value using [the formula](#pos-formula) +5. If the value at index pos is equal to the target, return 1 +6. If the value at index pos is greater than the target, set high to pos - 1 +7. If the value at index pos is less than the target, set low to pos + 1 +8. Repeat steps 3 - 7 +9. If the loop terminates and the target is not found, return 0 + +Time Complexity: O(log (log n))
+Space Complexity: O(1) + +#### pos formula: + +$$pos = {low+{(target-array[low])\times(high - low)\over(array[high]-array[low])}}$$ + +--- +### Linear Search: + +Algorithm Steps:
+1. Starting at the beginning of the array +2. Compare current value to the target +3. If the value is equal to the target then return 1 +4. If the value is not equal to the target then go to the next element +5. Repeat steps 2 - 4 until the end of array is reached +6. If the end of the array has been reached and target has not been found, return 0 + +Time Complexity: O(n)
+Space Complexity: O(1) + +--- +### Jump Search: + +Algorithm Steps: + +1. Initialize a variable called step and set it's value to $\sqrt{n}$ (where n is the length of the array) +2. Create a variable called prev and set it's value to 0 +3. While step is less than n, set prev to the value of step and then increment step by $\sqrt{n}$.
+If prev is greater than or equal to n, return false. Else if the value at index step is greater than target, break loop. +4. Initialize a loop starting at the value of prev until prev + $\sqrt{n}$ +5. If the current index is equal to the target, return 1 +6. If the current index is greater than the target, return 0 +7. Else repeat steps 5 - 6 until reached index corresponding to prev + $\sqrt{n}$ + +Time Complexity: O($\sqrt{n}$)
+Space Complexity: O(1) + +--- +### Tenary Search: + +Algorithm Steps: + +1. Intialise a variable called left with a value of 0 +2. Intialise a variable called right that is equal to the length of the array minus one +3. While left is less than or equal to right +4. Initialise a varible called mid1, calculate it's value using [the formula](#mid1-formula) +5. Initialise a varible called mid2, calculate it's value using [the formula](#mid2-formula) +6. If the value at index mid1 or mid2 is equal to the target, return 1 +7. If the value at index mid1 is less than the target, set right to mid1 - 1 +8. If the value at index mid2 is greater than the target, set left to mid2 + 1 +9. Else, set left to mid1 + 1 and set right to mid2 - 1 +10. Repeat steps 3 - 9 +11. If the loop terminates, return 0 + +Time Complexity: O(log3n)
+Space Complexity: O(1) + +#### mid1 formula: + +$mid1 = {left + (right - left) \div 3}$ + +#### mid2 formula: + +$mid2 = {right - (right - left) \div 3}$ + +--- + +Go to [README.md](../README.md) diff --git a/algorithms/SORTING.md b/algorithms/SORTING.md new file mode 100644 index 0000000..b136ef5 --- /dev/null +++ b/algorithms/SORTING.md @@ -0,0 +1,203 @@ +## Sorting Algorithms: + +Below is a table containing the sorting algorithms this project visualises.
+The links in the table direct to a information about the algorithm and its implementation steps. + +| Algorithm | +| --------------------------------------------- | +| [Bogo Sort](#bogo-sort) | +| [Brick Sort](#brick-sort) | +| [Bubble Sort](#bubble-sort) | +| [Cocktail Shaker Sort](#cocktail-shaker-sort) | +| [Gnome Sort](#gnome-sort) | +| [Insertion Sort](#insertion-sort) | +| [Merge Sort](#merge-sort) | +| [Quick Sort](#quick-sort) | +| [Selection Sort](#selection-sort) | +| [Tim Sort](#tim-sort) | + +--- +### Bogo Sort: + +Algorithm Steps: + +1. Randomly shuffle array +2. If array is sorted, stop. +3. If array is not sorted repeat step 1. + +Time Complexity: O((n + 1)!)
+Space Complexity: O(1) + +--- +### Brick Sort + +Algorithm steps: + +1. Create a variable names swapped and set it to true +2. While swapped is true, do +3. Set swapped to false +4. Iterate through the odd indexes of the array +5. If the element at the current odd index is greater than the element in the adjacent index, swap the elements and set swapped to true +6. Iterate through the even indexes of the array +7. If the element at the current even index is greater than the element in the adjacent index, swap the elements and set swapped to true + +Time Complexity: O(n2)
+Space Complexity: O(1) + +--- +### Bubble Sort: + +Algorithm steps: + +1. Loop through the array from left to right +2. At the beginning of each iteration set a boolean flag to False +3. In a nested loop, traverse from the beginning of the array to the end of the unsorted array using [this formula](#index-of-last-sorted-element-formula) +4. Compare the current element to the element adjacent to it +5. If the current element is greater than the adjacent elment, swap them and set the boolean flag to True +6. When the nested loop has terminated check the value of the boolean flag +7. If the boolean flag is True, continue for another iteration +8. If the boolean flag is False, the array is sorted and the algorithm should terminate. + +Time Complexity: O(n2)
+Space Complexity: O(1) + +#### End of unsorted array formula: + +$$ index = n - i - 1$$ + +n -> length of the array
+i -> index of current element + +--- +### Cocktail Shaker Sort + +Algorithm steps: + +1. Set a variable named swapped to true +2. While swapped is true do, +3. Set swapped to false +4. Iterate from the beginning of the array until the end comparing adjacent elements +5. If the element to the left if larger than the element to the right swap them and set swapped to true +6. If swapped is false, halt algorithm +7. Iterate from the end of the array to the beginning comparing adjacent elements +8. If the element to the left if larger than the element to the right swap them and set swapped to true + +Time Complexity: O(n2)
+Space Complexity: O(1) + +--- +### Gnome Sort + +Algorithm steps: + +1. Create a variable called pos and assign it the value 0 +2. While pos is less than the length of the array do +3. if pos is equal to 0, increment pos by one +4. if the element at pos is less than the element at pos - 1, swap them and decrement pos by one +5. else increment pos by one + +Time Complexity: O(n2)
+Space Complexity: O(1) + +--- +### Insertion Sort: + +Algorithm Steps: + +1. Consider the first element in the array as already sorted +2. Iterate through the array (starting at the second element) +3. Iterate from the current index minus one to the first index of the array +4. Compare the current unsorted element with the current element in the sorted array +5. If the unsorted element is greater than the sorted element, swap them +6. If sorted element is less than the unsorted, break the nested loop (the unsorted element is in the right place) + +Time Complexity: O(n2)
+Space Complexity: O(1) + +--- +### Merge Sort: + +Algorithm Steps: + +1. Divide the array into sub-arrays of size one. (Arrays of size one are considered sorted) +2. Compare the elements in each of the sub-arrays, inserting them in numerical order into a new sub-array +3. Repeat step 2 until all the sub-arrays have been merged leaving only one sorted array + +Time Complexity: O(n log n)
+Space Complexity: O(n) + + +#### A note on the Space Complexity + +An O(1) space complexity can be achieved by merging the sub arrays in-place. + +--- +### Quick Sort: + +Algorithm Steps: + +1. Initialise a variable called low and assign it the value 0 +2. Initialise a variavle called high and assign it the length of the array minus one +3. Select pivot using median of three +4. All elements less than the pivot must be placed to the left of the pivot +5. All elements greater than the pivot must be places to the right of the pivot +6. Two new pivots need to be selected to sort the separate halves of the array +7. The first pivot should be in the range, low to index of current pivot - 1 +8. The second pivot should be in the range, index of current pivot + 1 to end +9. Repeat steps 3 - 8 until low is greater than pivot index - 1 and pivot index + 1 is greater than end + +Time Complexity: O(n log n)
+Space Complexity: O(1) + +#### A note on the Time Complexity + +If the pivot is not chosen efficiently, the worst case time complexity becomes O(n2) + +#### Median of three + +- Get the elements at low, high and (low + high) / 2 +- Place the element in an array and sort +- The pivot is the middle value (element in index 1) + +--- +### Selection Sort: + +Algorithm Steps: + +1. Iterate through the array +2. Set a variable called minIdx to the current index +3. In a nested loop from the current index plus one to the end of the array +4. Find the index of the smallest element and store it in minIdx +5. Shift all elements between the current index and the smallest element index one place right +6. Place the smallest element into the current index + +Time Complexity: O(n2)
+Space Complexity: O(1) + +--- +### Tim Sort: + +Algorithm Steps: + +1. Calculate the minimum run size +2. Split the array into sub-arrays with sizes equal to the run size +3. Perform insertion sort on each of these sub arrays +4. Merge the sub-arrays using the same method as the merge sort +5. Repeatedly merge the sub-arrays until only one sorted array is lefy + +Time Complexity: O(n log n)
+Space Complexity: O(n) + +#### A note on the Space Complexity + +An O(1) space complexity can be achieved by merging the sub arrays in-place. + +#### Calculating run size + +Tim sort calculated the run size between the rangge of 32 - 64 (inclusive).
+For arrays that are smaller than 64, the algorithm just performs an insersion sort on the whole array.
+The process Tim Sort uses to calculate the run size can be found [here.](https://en.wikipedia.org/wiki/Timsort) + +--- + +Go to [README.md](../README.md) \ No newline at end of file diff --git a/algorithms/handlers/algorithm_names.py b/algorithms/handlers/algorithm_names.py index 5f43e06..8c8a1af 100644 --- a/algorithms/handlers/algorithm_names.py +++ b/algorithms/handlers/algorithm_names.py @@ -18,7 +18,7 @@ # Makes sure only files containing the algorithms are selected # Provided files containing algorithms follow the naming convention -> (name)_(algorithm type).py def filterFileNames(file : str, algorithmType : str) -> bool: - return True if file.split("_")[1] == f"{algorithmType}.py" else False + return True if file.split("_")[-1] == f"{algorithmType}.py" else False # Checks that relevant files follow inheritance and naming convenvtions # Checks if any class name has words "Algorithm" or "Search" in them @@ -55,7 +55,6 @@ def getAlgorithmNames(modules : list, algorithmsType : str) -> tuple: classType = algorithmsType.capitalize() # Imports relevant modules and gets relevant classes for module in modules: - # Imports module try: algorithmModule = importlib.import_module(f"algorithms.{algorithmsType}ing." + module) diff --git a/algorithms/sorting/brick_sort.py b/algorithms/sorting/brick_sort.py new file mode 100644 index 0000000..0eed651 --- /dev/null +++ b/algorithms/sorting/brick_sort.py @@ -0,0 +1,65 @@ +# If this isn't at the top the program breaks :/ +# If the file is run as is message this returned and program exits +if(__name__ == "__main__"): + print("This is file shouldn't be run on it's own. \nIt should be imported only.") + exit() + +from ..algorithm import Algorithm +class BrickSort(Algorithm): + # Constructor + def __init__(self, dataModel): + super().__init__(dataModel) + + # Returns algorithms name -> user sees this when selecting algorithm + def getName(self) -> str: + return "Brick Sort" + + # Brick Sort Algorithm + def brickSort(self) -> int: + # Length of the array + n = len(self.getArray()) + swapped = True + # While swapped is true + while(swapped): + swapped = False + # Iterate through odd indexes of the array + for i in range(1, n - 1, 2): + self.changeBarColour(i, "red") + self.updateArrayOnScreen() + self.delay() + # If elements are in the wrong the order + if(self.isSwapNeeded(i, i + 1)): + # Swap elements + self.swapElements(i, i + 1) + self.changeBarColour(i, "red") + self.updateArrayOnScreen() + self.delay() + swapped = True + + self.changeBarColour(i, "red") + self.updateArrayOnScreen() + self.delay() + + # If no swaps are performed + if(not swapped): break + + swapped = False + # Iterate through even indexes of the array + for i in range(0, n - 1, 2): + self.changeBarColour(i, "red") + self.updateArrayOnScreen() + self.delay() + # If elements are in the wrong the order + if(self.isSwapNeeded(i, i + 1)): + # Swap elements + self.swapElements(i, i + 1) + self.changeBarColour(i, "red") + self.updateArrayOnScreen() + self.delay() + swapped = True + self.updateArrayOnScreen() + self.delay() + self.coolEndingAnimation() + return 1 + +# Listen to Lithium by Nirvana \ No newline at end of file diff --git a/algorithms/sorting/cocktail_shaker_sort.py b/algorithms/sorting/cocktail_shaker_sort.py new file mode 100644 index 0000000..73f9527 --- /dev/null +++ b/algorithms/sorting/cocktail_shaker_sort.py @@ -0,0 +1,72 @@ +# If this isn't at the top the program breaks :/ +# If the file is run as is message this returned and program exits +if(__name__ == "__main__"): + print("This is file shouldn't be run on it's own. \nIt should be imported only.") + exit() + +from ..algorithm import Algorithm +class CocktailShakerSort(Algorithm): + # Constructor + def __init__(self, dataModel): + super().__init__(dataModel) + + # Returns algorithms name -> user sees this when selecting algorithm + def getName(self) -> str: + return "Cocktail Shaker Sort" + + # Cocktail Shaker Sort Algorithm + def cocktailShakerSort(self) -> int: + start = 0 + end = len(self.getArray()) - 1 + swapped = True + + # While elements have been swapped + while(swapped): + # Set swapped to false + swapped = False + # Iterate between indexes start and end + for i in range(start, end): + self.changeBarColour(i, "red") + self.updateArrayOnScreen() + self.delay() + + # If elements need to be swapped + if(self.isSwapNeeded(i, i + 1)): + # Swap them + self.swapElements(i, i + 1) + self.swapBarColours(i, i + 1) + # Set swapped to true + swapped = True + + self.changeBarColour(i, "red") + self.updateArrayOnScreen() + self.delay() + + # If no swaps were made, halt algorithm + if(not swapped): + self.updateArrayOnScreen() + self.delay() + self.coolEndingAnimation() + return 1 + + # Decrement end + end -= 1 + # Iterate between indexes end - 1 and start + 1 + for i in range(end - 1, start - 1, -1): + self.changeBarColour(i, "red") + self.updateArrayOnScreen() + self.delay() + # If elmenents need to be swapped, swap them + if(self.isSwapNeeded(i, i + 1)): + self.swapElements(i, i + 1) + # Set swapped to True + swapped = True + # Increment start + start += 1 + + self.updateArrayOnScreen() + self.delay() + self.coolEndingAnimation() + return 1 + +# Listen to What You Know by Two Door Cinema Club \ No newline at end of file diff --git a/algorithms/sorting/gnome_sort.py b/algorithms/sorting/gnome_sort.py new file mode 100644 index 0000000..c335ac9 --- /dev/null +++ b/algorithms/sorting/gnome_sort.py @@ -0,0 +1,48 @@ +# If this isn't at the top the program breaks :/ +# If the file is run as is message this returned and program exits +if(__name__ == "__main__"): + print("This is file shouldn't be run on it's own. \nIt should be imported only.") + exit() + +from ..algorithm import Algorithm +class GnomeSort(Algorithm): + # Constructor + def __init__(self, dataModel): + super().__init__(dataModel) + + # Returns algorithms name -> user sees this when selecting algorithm + def getName(self) -> str: + return "Gnome Sort" + + # Gnome Sort Algorithm + def gnomeSort(self) -> int: + # Length of the array + n = len(self.getArray()) + pos = 0 + # While pos is less than the length of the array + while(pos < n): + self.changeBarColour(pos, "red") + self.updateArrayOnScreen() + self.delay() + + # If pos is at the start of the array, increment pos + if(pos == 0): pos += 1 + # If element at pos and pos - 1 need to be swapped + if(self.isSwapNeeded(pos - 1, pos)): + self.swapElements(pos, pos - 1) + self.changeBarColour(pos - 1, "red") + self.updateArrayOnScreen() + self.delay() + # Decrement pos + pos -= 1 + # If elements at pos and pos - 1 are in the right place + else: + # Increment pos + pos += 1 + + self.updateArrayOnScreen() + self.delay() + self.coolEndingAnimation() + return 1 + +# Listen to Smells Like Teen Spirit by Nirvana \ No newline at end of file diff --git a/algorithms/sorting/insertion_sort.py b/algorithms/sorting/insertion_sort.py new file mode 100644 index 0000000..e9b005f --- /dev/null +++ b/algorithms/sorting/insertion_sort.py @@ -0,0 +1,49 @@ +# If this isn't at the top the program breaks :/ +# If the file is run as is message this returned and program exits +if(__name__ == "__main__"): + print("This is file shouldn't be run on it's own. \nIt should be imported only.") + exit() + + +from ..algorithm import Algorithm +class InsertionSort(Algorithm): + # Constructor + def __init__(self, dataModel): + super().__init__(dataModel) + + # Returns algorithms name -> user sees this when selecting algorithm + def getName(self) -> str: + return "Insertion Sort" + + # Stable Selection Sort Algorithm + def insertionSort(self) -> int: + n = len(self.getArray()) + # Iterate through array, the first element is considered as sorted + for i in range(1, n): + self.changeBarColour(i - 1, "orange") + self.changeBarColour(i, "red") + self.updateArrayOnScreen() + self.delay() + + # The left pointer keeps track of sorted element being compared to the sorted element + leftPtr = i - 1 + # The right pointer keeps track of the unsorted element + rightPtr = i + # Iterate until the start of the sorted array or + # the unsorted element is in the right place + while(leftPtr >= 0 and self.isSwapNeeded(leftPtr, rightPtr)): + # Swap elements indexes leftPtr, rightPtr + self.swapElements(leftPtr, rightPtr) + leftPtr -= 1 + rightPtr -= 1 + + self.changeBarColour(i, "orange") + self.changeBarColour(rightPtr, "red") + self.updateArrayOnScreen() + self.delay() + + self.coolEndingAnimation() + return 1 + + +# Listen to Highway to Hell by ACDC \ No newline at end of file diff --git a/algorithms/sorting/merge_sort.py b/algorithms/sorting/merge_sort.py index 74e10b3..555d79f 100644 --- a/algorithms/sorting/merge_sort.py +++ b/algorithms/sorting/merge_sort.py @@ -18,7 +18,7 @@ def getName(self) -> str: def mergeSort(self) -> int: # Call function to peform splitting into sub arrays self.mergeSortHelper(0, len(self.getArray()) - 1) - self.coolEndingAnimation() + self.coolEndingAnimation() return 1 def mergeSortHelper(self, leftPtr, rightPtr): diff --git a/algorithms/sorting/selection_sort.py b/algorithms/sorting/selection_sort.py index 31ecb81..c776612 100644 --- a/algorithms/sorting/selection_sort.py +++ b/algorithms/sorting/selection_sort.py @@ -38,7 +38,8 @@ def selectionSort(self) -> int: self.updateArrayOnScreen() self.delay() - self.coolEndingAnimation() + self.coolEndingAnimation() + return 1 # Shifts elements between the specified indexes one place right def __shiftRight(self, start, end): diff --git a/algorithms/sorting/tim_sort.py b/algorithms/sorting/tim_sort.py new file mode 100644 index 0000000..91da4d4 --- /dev/null +++ b/algorithms/sorting/tim_sort.py @@ -0,0 +1,124 @@ +# If this isn't at the top the program breaks :/ +# If the file is run as is message this returned and program exits +if(__name__ == "__main__"): + print("This is file shouldn't be run on it's own. \nIt should be imported only.") + exit() + + +from ..algorithm import Algorithm +class TimSort(Algorithm): + # Constructor + def __init__(self, dataModel): + super().__init__(dataModel) + self.__minRunSize = 4 + + # Returns algorithms name -> user sees this when selecting algorithm + def getName(self) -> str: + return "Tim Sort" + + # Tim Sort Algorithm + def timSort(self) -> int: + n = len(self.getArray()) + # Calculates the size of the run + runSize = self.__calcMinRinSize(n) + + for i in range(0, n, runSize): + # Perform insertion sort on each run + self.insertionSort(i, min((i + runSize) - 1, n - 1)) + + # While run size is less than the size of the array + while(runSize < n): + # Iterate through each pair of sub arrays + for i in range(0, n, runSize * 2): + # Ending index of the right sub array + rightPtr = min(i + (runSize * 2) - 1, n - 1) + # Starting index of the right sub array + rightArrStart = min(i + runSize, n - 1) + # There can be an odd number of runs meaning one sub array is leftover and can't be merged + # It's pointless to merge a sub array with itself + # So this check make sure merging is performed on two sub arrays only + if(rightArrStart < rightPtr): + self.mergeSubArrays(i, rightArrStart, rightPtr) + # Doubles run size has now the number of sub arrays as halved + # but they are now double in size + runSize *= 2 + + self.updateArrayOnScreen() + self.delay() + self.coolEndingAnimation() + return 1 + + + def mergeSubArrays(self, start, mid, end): + leftPtr = start + rightPtr = mid + + while(leftPtr <= mid - 1 and rightPtr <= end): + self.changeBarColour(leftPtr, "red") + self.updateArrayOnScreen() + self.delay() + + if(self.isSwapNeeded(leftPtr, rightPtr)): + self.shiftElements(leftPtr, rightPtr) + leftPtr += 1 + rightPtr += 1 + mid += 1 + else: leftPtr += 1 + + def shiftElements(self, leftPtr, rightPtr): + # Stores value at index rightPtr (as it is overwritten later) + value = self.getElement(rightPtr) + index = rightPtr + # Iterate until index = leftPtr + while(index != leftPtr): + # Shift element at index one place to the left + self.swapElements(index, index - 1) + index -= 1 + self.changeElement(index, value) + self.changeBarColour(rightPtr, "red") + self.updateArrayOnScreen() + self.delay() + + def insertionSort(self, start, end): + # Iterate between the indexes + for i in range(start + 1, end + 1): + self.changeBarColour(i - 1, "orange") + self.changeBarColour(i, "red") + self.updateArrayOnScreen() + self.delay() + + # The left pointer keeps track of sorted element being compared to the sorted element + leftPtr = i - 1 + # The right pointer keeps track of the unsorted element + rightPtr = i + + # Iterate until the beginning of the sorted array or + # until the unsorted element is in the right place + while(leftPtr >= start and self.isSwapNeeded(leftPtr, rightPtr)): + # Swap elements at the specified indexes + self.swapElements(leftPtr, rightPtr) + # Adjust the pointers + leftPtr -= 1 + rightPtr -= 1 + + self.changeBarColour(i, "orange") + self.changeBarColour(rightPtr, "red") + self.updateArrayOnScreen() + self.delay() + + def __calcMinRinSize(self, n : int) -> int: + # If the length of the array is less than 64, the runsize is set to 4 + # This is done for visualisation purposes, the actual implementation + # would just perform an insertion sort + if(n < 64): return self.__minRunSize + # Gets binary representation of the number + binVal = bin(n) + # Denary representation of the six most significant bits + # The index slicing starts at index 2 as the string returned + # by the bin() function starts with 0b + runSize = int(binVal[2:8], 2) + # Add one to the run size oif any of the reamining bits are still set + if(binVal[8:].count("1") >= 1): return runSize + 1 + return runSize + +# Listen to No Surprises by Radiohead \ No newline at end of file diff --git a/screens/screen_template/screens_template.py b/screens/screen_template/screens_template.py index 0483878..137cc8c 100644 --- a/screens/screen_template/screens_template.py +++ b/screens/screen_template/screens_template.py @@ -151,5 +151,4 @@ def loadHomeScreen(self) -> None: def getHomeButton(self) -> tk.Button: return self.__homeButton - # Listen to Under You by Foo Fighters \ No newline at end of file diff --git a/screens/shared_layout/shared_layout.py b/screens/shared_layout/shared_layout.py index d5e64f0..1684ecc 100644 --- a/screens/shared_layout/shared_layout.py +++ b/screens/shared_layout/shared_layout.py @@ -193,7 +193,7 @@ def __getAlgorithmChoice(self) -> str: return self.__algorithmOptions.get() def __getAlgorithmType(self) -> str: - return self.__algorithmOptions.get().split(" ")[1].lower() + return self.__algorithmOptions.get().split(" ")[-1].lower() def __setDelay(self) -> None: if(self.__isMilliSeconds): diff --git a/screens/shared_layout/shared_model.py b/screens/shared_layout/shared_model.py index 32b96d5..587de13 100644 --- a/screens/shared_layout/shared_model.py +++ b/screens/shared_layout/shared_model.py @@ -78,4 +78,4 @@ def getDefaultResolution(self): return self.__defaultResolution # Gets the buffer used when selecting a target outside the array def getBuffer(self): return self.__buffer -# Listen to Last Nite by The Strokes \ No newline at end of file +# Listen to The Adults Are Talking by The Strokes \ No newline at end of file