Skip to content

Commit 0de898f

Browse files
feat: add cycle sort algorithm (TheAlgorithms#634)
* feat: add cycle sort algorithm * feat: add cycle sort algorithm * feat: address code review comments * feat: address code review comments * Remove unnecessary newline --------- Co-authored-by: Taj <[email protected]>
1 parent a0bc6d6 commit 0de898f

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

sort/cyclesort.go

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package sort
2+
3+
import (
4+
"github.com/TheAlgorithms/Go/constraints"
5+
)
6+
7+
// Cycle sort is an in-place, unstable sorting algorithm that is particularly useful
8+
// when sorting arrays containing elements with a small range of values. It is theoretically
9+
// optimal in terms of the total number of writes to the original array.
10+
func Cycle[T constraints.Number](arr []T) []T {
11+
counter, cycle, len := 0, 0, len(arr)
12+
// Early return if the array too small
13+
if len <= 1 {
14+
return arr
15+
}
16+
17+
for cycle = 0; cycle < len-1; cycle++ {
18+
elem := arr[cycle]
19+
// Find total smaller elements to right
20+
pos := cycle
21+
for counter = cycle + 1; counter < len; counter++ {
22+
if arr[counter] < elem {
23+
pos++
24+
}
25+
}
26+
// In case this element is already in correct position, let's skip processing
27+
if pos == cycle {
28+
continue
29+
}
30+
// In case we have same elements, we want to skip to the end of that list as well, ignoring order
31+
// This makes the algorithm unstable for composite elements
32+
for elem == arr[pos] {
33+
pos++
34+
}
35+
// Now let us put the item to it's right position
36+
arr[pos], elem = elem, arr[pos]
37+
38+
//We need to rotate the array till we have reached the start of the cycle again
39+
for pos != cycle {
40+
pos = cycle
41+
// Find smaller elements to right again
42+
for counter = cycle + 1; counter < len; counter++ {
43+
if arr[counter] < elem {
44+
pos++
45+
}
46+
}
47+
for elem == arr[pos] {
48+
pos++
49+
}
50+
//We can do this unconditionally, but the check helps prevent redundant writes to the array
51+
if elem != arr[pos] {
52+
arr[pos], elem = elem, arr[pos]
53+
}
54+
}
55+
}
56+
57+
return arr
58+
}

sort/sorts_test.go

+8
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ func TestPatience(t *testing.T) {
169169
testFramework(t, sort.Patience[int])
170170
}
171171

172+
func TestCycle(t *testing.T) {
173+
testFramework(t, sort.Cycle[int])
174+
}
175+
172176
//END TESTS
173177

174178
func benchmarkFramework(b *testing.B, f func(arr []int) []int) {
@@ -286,3 +290,7 @@ func BenchmarkPigeonhole(b *testing.B) {
286290
func BenchmarkPatience(b *testing.B) {
287291
benchmarkFramework(b, sort.Patience[int])
288292
}
293+
294+
func BenchmarkCycle(b *testing.B) {
295+
benchmarkFramework(b, sort.Cycle[int])
296+
}

0 commit comments

Comments
 (0)