-
Notifications
You must be signed in to change notification settings - Fork 0
/
Cycle Sort.fs
60 lines (48 loc) · 2.01 KB
/
Cycle Sort.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/// Contains the cycle sort implementation.
[<CompilationRepresentation (CompilationRepresentationFlags.ModuleSuffix)>]
module NikonTheThird.SortingAlgorithms.Algorithms.CycleSort
open NikonTheThird.SortingAlgorithms.Algorithm
/// https://en.wikipedia.org/wiki/Cycle_sort
[<Algorithm "Cycle Sort">]
let cycleSort : Algorithm = algorithm {
let! count = getCount
// Loop through the array to find cycles to rotate.
for cycleStart = 0 to count - 2 do
let! label = setLabel' (Primary cycleStart) "0"
let cycleLabels = ResizeArray [label]
let rec skipEquals pos = algorithm {
if pos = cycleStart then return pos else
match! compare cycleStart pos with
| Equal -> return! skipEquals (pos + 1)
| _ -> return pos
}
// Find where to put the item.
let mutable pos = cycleStart
for i = cycleStart + 1 to count - 1 do
match! compare i cycleStart with
| LessThan -> do pos <- pos + 1
| _ -> do ()
// If the item is already there, this is not a cycle.
if pos = cycleStart then do label.Dispose () else
// Otherwise, put the item there or after any duplicates.
let! pos' = skipEquals pos
do pos <- pos'
do! swap cycleStart pos
// Rotate the rest of the cycle.
while pos <> cycleStart do
let! label = setLabel' (Primary cycleStart) (string cycleLabels.Count)
do cycleLabels.Add label
// Find where to put the item.
do pos <- cycleStart
for i = cycleStart + 1 to count - 1 do
match! compare i cycleStart with
| LessThan -> do pos <- pos + 1
| _ -> do ()
// Put the item there or after any duplicates.
let! pos' = skipEquals pos
do pos <- pos'
do! swap cycleStart pos
// Remove all the labes of this cycle.
for label in cycleLabels do
do label.Dispose ()
}