-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from smoreg/smoreg_cycle_sort
Add cycle sort implementation
- Loading branch information
Showing
4 changed files
with
119 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Cycle Sort | ||
Cycle sort is an in-place, unstable sorting algorithm, a comparison sort that is theoretically optimal in terms of the total number of writes to the original array, unlike any other in-place sorting algorithm. It is based on the idea that the permutation to be sorted can be factored into cycles, which can individually be rotated to give a sorted result. | ||
Unlike nearly every other sort, items are never written elsewhere in the array simply to push them out of the way of the action. Each value is either written zero times, if it's already in its correct position, or written one time to its correct position. This matches the minimal number of overwrites required for a completed in-place sort. | ||
|
||
### Algorithm | ||
1. Get a list of unsorted numbers | ||
2. Remember current CycleStartPosition as 0 | ||
3. If CycleStartPosition > lenght of list go to step 9. Else remember element on CycleStartPosition as A. | ||
4. Iterate through array, find number of elements lesser than current. Find by that correct position for current element. | ||
5. If the element is already at the correct position, increase CycleStartPosition by one and go to step 3. If it is not, write it to its intended position. That position is inhabited by a different element B. | ||
6. Find correct position for B. | ||
7. If correct position for B == CycleStartPosition, write it, increase CycleStartPosition by one and go to step 3. | ||
8. If it is not, write it to its intended position. That position is inhabited by a different element C. Remember C as B and go to step 6. | ||
9. Stop | ||
|
||
### Example | ||
``` | ||
array : [55 52 79 20 65 26 36 93 97 22] | ||
[55 52 79 20 65 55 36 93 97 22] | ||
[55 52 26 20 65 55 36 93 97 22] | ||
[55 52 26 20 65 55 36 79 97 22] | ||
[55 52 26 20 65 55 36 79 93 22] | ||
[55 52 26 20 65 55 36 79 93 97] | ||
[55 22 26 20 65 55 36 79 93 97] | ||
[55 22 26 20 52 55 36 79 93 97] | ||
[55 22 26 20 52 55 65 79 93 97] | ||
[55 22 26 36 52 55 65 79 93 97] | ||
[20 22 26 36 52 55 65 79 93 97] | ||
``` | ||
|
||
### Complexity | ||
``` | ||
Worst-case performance Θ(n2) | ||
Best-case performance Θ(n2) | ||
Average performance Θ(n2) | ||
Worst-case space complexity Θ(n) total, Θ(1) auxiliary | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package sort | ||
|
||
// CycleSort ... | ||
// 1) get element | ||
// 2) Find that element position | ||
// 3) place it to right place | ||
// 4) get previous position element, go to step 2 | ||
func CycleSort(a []int) []int { | ||
for cycleStart, mainCycleItem := range a { | ||
item := mainCycleItem | ||
pos := cycleStart | ||
pos = getElementRealPosition(pos, cycleStart, item, a) | ||
if pos == cycleStart { | ||
continue // element at right place! | ||
} | ||
for item == a[pos] { | ||
pos += 1 | ||
} | ||
a[pos], item = item, a[pos] | ||
for pos != cycleStart { // pos == cycleStart => new element at right place! | ||
pos = getElementRealPosition(pos, cycleStart, item, a) | ||
for item == a[pos] { | ||
pos += 1 | ||
} | ||
a[pos], item = item, a[pos] | ||
} | ||
} | ||
return a | ||
} | ||
|
||
func getElementRealPosition(pos, cycleStart, item int, a []int) int { | ||
pos = cycleStart | ||
for i := cycleStart + 1; i < len(a); i++ { | ||
if a[i] < item { | ||
pos += 1 | ||
} | ||
} | ||
return pos | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package sort | ||
|
||
import ( | ||
"math/rand" | ||
"sort" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
// TestCycleSort ... Test if the program actually sorts array or not | ||
func TestCycleSort(t *testing.T) { | ||
randomUnsortedSlice, randomSortedSlice := generateRandomSlices() | ||
assert.NotEqual(t, randomUnsortedSlice, randomSortedSlice) | ||
|
||
cycleSorted := CycleSort(randomUnsortedSlice) | ||
|
||
assert.Equal(t, randomSortedSlice, cycleSorted, "Oops.. Cycle sort didn't work!!") | ||
} | ||
|
||
// generateRandomSlices generate random slice and his sorted copy | ||
func generateRandomSlices() (unsorted []int, sorted []int) { | ||
rand.Seed(time.Now().UnixNano()) | ||
size := rand.Intn(100) | ||
randomUnsortedSlice := make([]int, size, size) | ||
for i := 0; i < size; i++ { | ||
randomUnsortedSlice[i] = rand.Intn(999) | ||
} | ||
randomSortedSlice := append([]int(nil), randomUnsortedSlice...) // Notice the ... splat | ||
sort.Ints(randomSortedSlice) | ||
return randomUnsortedSlice, randomSortedSlice | ||
} |