-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathsort.go
103 lines (93 loc) · 2.09 KB
/
sort.go
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package fgbase
import (
"sort"
)
// These are sort.min, sort.medianOfThree, sort.swapRange, and sort.doPivot, borrowed
// under the GO-LICENSE from go 1.4.2. Required to reuse sort.doPivot.
func min(a, b int) int {
if a < b {
return a
}
return b
}
// medianOfThree moves the median of the three values data[a], data[b], data[c] into data[a].
func medianOfThree(data sort.Interface, a, b, c int) {
m0 := b
m1 := a
m2 := c
// bubble sort on 3 elements
if data.Less(m1, m0) {
data.Swap(m1, m0)
}
if data.Less(m2, m1) {
data.Swap(m2, m1)
}
if data.Less(m1, m0) {
data.Swap(m1, m0)
}
// now data[m0] <= data[m1] <= data[m2]
}
func swapRange(data sort.Interface, a, b, n int) {
for i := 0; i < n; i++ {
data.Swap(a+i, b+i)
}
}
func doPivot(data sort.Interface, lo, hi int) (midlo, midhi int) {
m := lo + (hi-lo)/2 // Written like this to avoid integer overflow.
if hi-lo > 40 {
// Tukey's ``Ninther,'' median of three medians of three.
s := (hi - lo) / 8
medianOfThree(data, lo, lo+s, lo+2*s)
medianOfThree(data, m, m-s, m+s)
medianOfThree(data, hi-1, hi-1-s, hi-1-2*s)
}
medianOfThree(data, lo, m, hi-1)
// Invariants are:
// data[lo] = pivot (set up by ChoosePivot)
// data[lo <= i < a] = pivot
// data[a <= i < b] < pivot
// data[b <= i < c] is unexamined
// data[c <= i < d] > pivot
// data[d <= i < hi] = pivot
//
// Once b meets c, can swap the "= pivot" sections
// into the middle of the slice.
pivot := lo
a, b, c, d := lo+1, lo+1, hi, hi
for {
for b < c {
if data.Less(b, pivot) { // data[b] < pivot
b++
} else if !data.Less(pivot, b) { // data[b] = pivot
data.Swap(a, b)
a++
b++
} else {
break
}
}
for b < c {
if data.Less(pivot, c-1) { // data[c-1] > pivot
c--
} else if !data.Less(c-1, pivot) { // data[c-1] = pivot
data.Swap(c-1, d-1)
c--
d--
} else {
break
}
}
if b >= c {
break
}
// data[b] > pivot; data[c-1] < pivot
data.Swap(b, c-1)
b++
c--
}
n := min(b-a, a-lo)
swapRange(data, lo, b-n, n)
n = min(hi-d, d-c)
swapRange(data, c, hi-n, n)
return lo + b - a, hi - (d - c)
}