From 394a4e6311a31aee4521506725148e5a6a0216ab Mon Sep 17 00:00:00 2001 From: Vedant Shringari Date: Wed, 25 Sep 2024 16:39:43 -0400 Subject: [PATCH 1/2] Refactor cycle_sort and add comprehensive test cases Refactored cycle_sort for improved readability and conciseness by simplifying the nested loops and removing redundant comments. Added multiple test cases to cover various scenarios, including already sorted, reverse sorted, single element, empty arrays, arrays with duplicates, large random arrays, and arrays with negative numbers. --- algorithms/sort/cycle_sort.py | 73 +++++++++++++++-------------------- tests/test_sort.py | 24 ++++++++++++ 2 files changed, 56 insertions(+), 41 deletions(-) diff --git a/algorithms/sort/cycle_sort.py b/algorithms/sort/cycle_sort.py index 6e512c924..b754992db 100644 --- a/algorithms/sort/cycle_sort.py +++ b/algorithms/sort/cycle_sort.py @@ -1,46 +1,37 @@ -def cycle_sort(arr): - """ - cycle_sort - This is based on the idea that the permutations to be sorted - can be decomposed into cycles, - and the results can be individually sorted by cycling. - - reference: https://en.wikipedia.org/wiki/Cycle_sort - - Average time complexity : O(N^2) - Worst case time complexity : O(N^2) - """ - len_arr = len(arr) - # Finding cycle to rotate. - for cur in range(len_arr - 1): - item = arr[cur] +""" +cycle_sort +This is based on the idea that the permutations to be sorted +can be decomposed into cycles, +and the results can be individually sorted by cycling. - # Finding an indx to put items in. - index = cur - for i in range(cur + 1, len_arr): - if arr[i] < item: - index += 1 +reference: https://en.wikipedia.org/wiki/Cycle_sort - # Case of there is not a cycle - if index == cur: +Average time complexity : O(N^2) +Worst case time complexity : O(N^2) +""" +def cycle_sort(arr): + # writes = 0 + for cycleStart in range(0, len(arr)-1): + currElement = arr[cycleStart] + currPos = cycleStart + for i in range(cycleStart+1, len(arr)): + if arr[i] < currElement: + currPos += 1 + if currPos == cycleStart: continue + while currElement == arr[currPos]: + currPos += 1 + arr[currPos], currElement = currElement, arr[currPos] + # writes += 1 - # Putting the item immediately right after the duplicate item or on the right. - while item == arr[index]: - index += 1 - arr[index], item = item, arr[index] - - # Rotating the remaining cycle. - while index != cur: - - # Finding where to put the item. - index = cur - for i in range(cur + 1, len_arr): - if arr[i] < item: - index += 1 - - # After item is duplicated, put it in place or put it there. - while item == arr[index]: - index += 1 - arr[index], item = item, arr[index] + while currPos != cycleStart: + currPos = cycleStart + for j in range(cycleStart+1, len(arr)): + if arr[j] < currElement: + currPos += 1 + while currElement == arr[currPos]: + currPos += 1 + arr[currPos], currElement = currElement, arr[currPos] + # writes += 1 + # print(writes) return arr diff --git a/tests/test_sort.py b/tests/test_sort.py index c80290fdf..7ffe1c860 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -57,6 +57,30 @@ def test_counting_sort(self): def test_cycle_sort(self): self.assertTrue(is_sorted(cycle_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) + def test_cycle_sort_already_sorted(self): + self.assertTrue(is_sorted(cycle_sort([1, 2, 3, 4, 5, 6, 7, 8, 9]))) + + def test_cycle_sort_reverse_sorted(self): + self.assertTrue(is_sorted(cycle_sort([9, 8, 7, 6, 5, 4, 3, 2, 1]))) + + def test_cycle_sort_single_element(self): + self.assertEqual(cycle_sort([42]), [42]) + + def test_cycle_sort_empty_array(self): + self.assertEqual(cycle_sort([]), []) + + def test_cycle_sort_with_duplicates(self): + self.assertTrue(is_sorted(cycle_sort([4, 1, 3, 2, 2, 5, 5, 1]))) + + def test_cycle_sort_large_random_array(self): + import random + random_array = random.sample(range(1, 1001), 100) + sorted_array = sorted(random_array) + self.assertEqual(cycle_sort(random_array), sorted_array) + + def test_cycle_sort_negative_numbers(self): + self.assertTrue(is_sorted(cycle_sort([-5, -1, -3, 2, 0, 1]))) + def test_exchange_sort(self): self.assertTrue(is_sorted(exchange_sort([1, 3, 2, 5, 65, 23, 57, 1232]))) From 13b378afa8c0f24183023734e84ba0a0ab895fc3 Mon Sep 17 00:00:00 2001 From: Vedant Shringari Date: Wed, 25 Sep 2024 17:00:50 -0400 Subject: [PATCH 2/2] Refactor cycle_sort and add comprehensive test cases Refactored cycle_sort for improved readability and conciseness by simplifying the nested loops and removing redundant comments. Added multiple test cases to cover various scenarios, including already sorted, reverse sorted, single element, empty arrays, arrays with duplicates, large random arrays, and arrays with negative numbers. --- algorithms/sort/cycle_sort.py | 58 ++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/algorithms/sort/cycle_sort.py b/algorithms/sort/cycle_sort.py index b754992db..70425d22a 100644 --- a/algorithms/sort/cycle_sort.py +++ b/algorithms/sort/cycle_sort.py @@ -1,37 +1,67 @@ -""" -cycle_sort -This is based on the idea that the permutations to be sorted -can be decomposed into cycles, -and the results can be individually sorted by cycling. +def cycle_sort(arr): + """ + Sorts an array in place using the Cycle Sort algorithm. -reference: https://en.wikipedia.org/wiki/Cycle_sort + Cycle Sort is a comparison-based, in-place, and non-comparing sorting algorithm that is particularly useful for + minimizing the number of writes to the original array. It is based on the idea of dividing the array into + cycles and rotating the elements in each cycle to their correct positions. -Average time complexity : O(N^2) -Worst case time complexity : O(N^2) -""" -def cycle_sort(arr): - # writes = 0 + Parameters: + arr (list): A list of elements (numbers) to be sorted. The function modifies this list in place. + + Returns: + list: The sorted list. + + Complexity: + - Time Complexity: O(n^2) in the worst case, where n is the number of elements in the array. + - Space Complexity: O(1) since the sorting is done in place. + + Algorithm Steps: + 1. Iterate through each element in the array using a variable `cycleStart`. + 2. For each element, determine its correct position in the sorted array by counting how many elements + are less than the current element (`currElement`). + 3. If the current position (`currPos`) is the same as `cycleStart`, it means the element is already in + the correct position, so continue to the next element. + 4. If not, swap the current element with the element at its correct position. + 5. Repeat the process until the cycle is complete and all elements are in their sorted position. + + Note: This implementation currently does not count the number of writes made to the array, as indicated by + the commented-out `writes` variable. + """ for cycleStart in range(0, len(arr)-1): currElement = arr[cycleStart] currPos = cycleStart + + # Determine the position where the current element should go for i in range(cycleStart+1, len(arr)): if arr[i] < currElement: currPos += 1 + + # If the element is already in the correct position, skip to the next if currPos == cycleStart: continue + + # Find the next position of the current element, in case of duplicates while currElement == arr[currPos]: currPos += 1 + + # Swap the current element to its correct position arr[currPos], currElement = currElement, arr[currPos] - # writes += 1 + # Continue the cycle for the element moved to its correct position while currPos != cycleStart: currPos = cycleStart + + # Determine the new position for the current element for j in range(cycleStart+1, len(arr)): if arr[j] < currElement: currPos += 1 + + # Find the next position of the current element, in case of duplicates while currElement == arr[currPos]: currPos += 1 + + # Swap the current element to its correct position arr[currPos], currElement = currElement, arr[currPos] - # writes += 1 - # print(writes) + return arr