From 543540c6105dca941b45c6a04cc019f48a9de7fa Mon Sep 17 00:00:00 2001 From: Aditya Pal Date: Fri, 28 Apr 2023 15:57:06 +0530 Subject: [PATCH 1/5] feat: add cycle sort algorithm --- sort/cyclesort.go | 67 ++++++++++++++++++++++++++++++++++++++++++++++ sort/sorts_test.go | 11 +++++++- 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 sort/cyclesort.go diff --git a/sort/cyclesort.go b/sort/cyclesort.go new file mode 100644 index 000000000..e17b2bb14 --- /dev/null +++ b/sort/cyclesort.go @@ -0,0 +1,67 @@ +package sort + +import ( + "github.com/TheAlgorithms/Go/constraints" +) + +// Cycle sort is an in-place, unstable sorting algorithm that is particularly useful +// when sorting arrays containing elements with a small range of values. It is theoretically +// optimal in terms of the total number of writes to the original array. +func Cycle[T constraints.Number](arr []T) []T { + + counter, cycle, len := 0, 0, len(arr) + + // Early return if the array too small + if len <= 1 { + return arr + } + + for cycle = 0; cycle < len-1; cycle++ { + elem := arr[cycle] + // Find total smaller elements to right + pos := cycle + for counter = cycle + 1; counter < len; counter++ { + if arr[counter] < elem { + pos++ + } + } + + // In case this element is already in correct position, let's skip processing + if pos == cycle { + continue + } + + // In case we have same elements, we want to skip to the end of that list as well, ignoring order + // This makes the algorithm unstable for composite elements + for elem == arr[pos] { + pos++ + } + + // Now let us put the item to it's right position + arr[pos], elem = elem, arr[pos] + + //We need to rotate the array till we have reached the start of the cycle again + for pos != cycle { + pos = cycle + + // Find smaller elements to right again + for counter = cycle + 1; counter < len; counter++ { + if arr[counter] < elem { + pos++ + } + } + + // Ignore all duplicate elements, if any still appear + for elem == arr[pos] { + pos++ + } + + //We can do this unconditionally, but the check helps prevent redundant writes to the array + if elem != arr[pos] { + arr[pos], elem = elem, arr[pos] + } + } + } + + return arr +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 7ff8b4363..fc0a505e1 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -1,11 +1,12 @@ package sort_test import ( - "github.com/TheAlgorithms/Go/sort" "math/rand" "reflect" "testing" "time" + + "github.com/TheAlgorithms/Go/sort" ) func testFramework(t *testing.T, sortingFunction func([]int) []int) { @@ -169,6 +170,10 @@ func TestPatience(t *testing.T) { testFramework(t, sort.Patience[int]) } +func TestCycle(t *testing.T) { + testFramework(t, sort.Cycle[int]) +} + //END TESTS func benchmarkFramework(b *testing.B, f func(arr []int) []int) { @@ -286,3 +291,7 @@ func BenchmarkPigeonhole(b *testing.B) { func BenchmarkPatience(b *testing.B) { benchmarkFramework(b, sort.Patience[int]) } + +func BenchmarkCycle(b *testing.B) { + benchmarkFramework(b, sort.Cycle[int]) +} From d02aeb8dc5adde74f3aadd204f9a212ef02fc8af Mon Sep 17 00:00:00 2001 From: Aditya Pal Date: Fri, 28 Apr 2023 16:03:15 +0530 Subject: [PATCH 2/5] feat: add cycle sort algorithm --- sort/sorts_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sort/sorts_test.go b/sort/sorts_test.go index fc0a505e1..aeb90c04e 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -1,12 +1,11 @@ package sort_test import ( + "github.com/TheAlgorithms/Go/sort" "math/rand" "reflect" "testing" "time" - - "github.com/TheAlgorithms/Go/sort" ) func testFramework(t *testing.T, sortingFunction func([]int) []int) { From e364b8b0afe5cdf1c2ba57376fb09f5bf98ce233 Mon Sep 17 00:00:00 2001 From: Aditya Pal Date: Fri, 28 Apr 2023 17:11:39 +0530 Subject: [PATCH 3/5] feat: address code review comments --- sort/cyclesort.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sort/cyclesort.go b/sort/cyclesort.go index e17b2bb14..421be7ec0 100644 --- a/sort/cyclesort.go +++ b/sort/cyclesort.go @@ -10,12 +10,11 @@ import ( func Cycle[T constraints.Number](arr []T) []T { counter, cycle, len := 0, 0, len(arr) - // Early return if the array too small if len <= 1 { return arr } - + for cycle = 0; cycle < len-1; cycle++ { elem := arr[cycle] // Find total smaller elements to right @@ -25,37 +24,30 @@ func Cycle[T constraints.Number](arr []T) []T { pos++ } } - // In case this element is already in correct position, let's skip processing if pos == cycle { continue } - // In case we have same elements, we want to skip to the end of that list as well, ignoring order // This makes the algorithm unstable for composite elements for elem == arr[pos] { pos++ } - // Now let us put the item to it's right position arr[pos], elem = elem, arr[pos] //We need to rotate the array till we have reached the start of the cycle again for pos != cycle { pos = cycle - // Find smaller elements to right again for counter = cycle + 1; counter < len; counter++ { if arr[counter] < elem { pos++ } } - - // Ignore all duplicate elements, if any still appear for elem == arr[pos] { pos++ } - //We can do this unconditionally, but the check helps prevent redundant writes to the array if elem != arr[pos] { arr[pos], elem = elem, arr[pos] From 465f648c991762fb571812957cfa30415c119cae Mon Sep 17 00:00:00 2001 From: Aditya Pal Date: Fri, 28 Apr 2023 17:17:11 +0530 Subject: [PATCH 4/5] feat: address code review comments --- sort/cyclesort.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sort/cyclesort.go b/sort/cyclesort.go index 421be7ec0..294b64d3a 100644 --- a/sort/cyclesort.go +++ b/sort/cyclesort.go @@ -14,7 +14,7 @@ func Cycle[T constraints.Number](arr []T) []T { if len <= 1 { return arr } - + for cycle = 0; cycle < len-1; cycle++ { elem := arr[cycle] // Find total smaller elements to right From 90b5b6b2f4a9943b03166d2c56cd474f1a1c5ef1 Mon Sep 17 00:00:00 2001 From: Taj Date: Fri, 28 Apr 2023 13:39:57 +0100 Subject: [PATCH 5/5] Remove unnecessary newline --- sort/cyclesort.go | 1 - 1 file changed, 1 deletion(-) diff --git a/sort/cyclesort.go b/sort/cyclesort.go index 294b64d3a..611fe27c2 100644 --- a/sort/cyclesort.go +++ b/sort/cyclesort.go @@ -8,7 +8,6 @@ import ( // when sorting arrays containing elements with a small range of values. It is theoretically // optimal in terms of the total number of writes to the original array. func Cycle[T constraints.Number](arr []T) []T { - counter, cycle, len := 0, 0, len(arr) // Early return if the array too small if len <= 1 {