aboutsummaryrefslogtreecommitdiff
path: root/src/sort
diff options
context:
space:
mode:
authorJosh Bleecher Snyder <josharian@gmail.com>2014-12-18 13:11:08 -0800
committerJosh Bleecher Snyder <josharian@gmail.com>2014-12-22 21:17:43 +0000
commit2a617d46f3ed39a71d8af8fb004fdfe8711160c2 (patch)
treefce1c0f1b781f7d516c7f2fa25ce0a0acb52791c /src/sort
parenta48e789635788d4cab23f76b4adc74e5fa343d24 (diff)
downloadgo-2a617d46f3ed39a71d8af8fb004fdfe8711160c2.tar.gz
go-2a617d46f3ed39a71d8af8fb004fdfe8711160c2.zip
sort: reduce leaf calls in Stable
Move the symMerge recursion stopping condition from the beginning of symMerge to the callers. This halves the number of calls to symMerge while running 'go test sort'. benchmark old ns/op new ns/op delta BenchmarkStable1e6 8358117060 7954143849 -4.83% BenchmarkStable1e4 40116117 38583285 -3.82% BenchmarkStableInt1K 119150 115182 -3.33% BenchmarkStableInt64K 9799845 9515475 -2.90% BenchmarkStableString1K 388901 393516 +1.19% BenchmarkStable1e2 124917 123618 -1.04% Change-Id: I7ba2ca277f213b076fe6830e1139edb47ac53800 Reviewed-on: https://go-review.googlesource.com/1820 Reviewed-by: Robert Griesemer <gri@golang.org>
Diffstat (limited to 'src/sort')
-rw-r--r--src/sort/sort.go22
1 files changed, 14 insertions, 8 deletions
diff --git a/src/sort/sort.go b/src/sort/sort.go
index 63f8894a19..55134956c0 100644
--- a/src/sort/sort.go
+++ b/src/sort/sort.go
@@ -316,7 +316,7 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
// data.Less and O(n*log(n)*log(n)) calls to data.Swap.
func Stable(data Interface) {
n := data.Len()
- blockSize := 20
+ blockSize := 20 // must be > 0
a, b := 0, blockSize
for b <= n {
insertionSort(data, a, b)
@@ -332,7 +332,9 @@ func Stable(data Interface) {
a = b
b += 2 * blockSize
}
- symMerge(data, a, a+blockSize, n)
+ if m := a + blockSize; m < n {
+ symMerge(data, a, m, n)
+ }
blockSize *= 2
}
}
@@ -352,11 +354,11 @@ func Stable(data Interface) {
// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
// in the paper carries through for Swap operations, especially as the block
// swapping rotate uses only O(M+N) Swaps.
+//
+// symMerge assumes non-degenerate arguments: a < m && m < b.
+// Having the caller check this condition eliminates many leaf recursion calls,
+// which improves performance.
func symMerge(data Interface, a, m, b int) {
- if a >= m || m >= b {
- return
- }
-
mid := a + (b-a)/2
n := mid + m
var start, r int
@@ -380,8 +382,12 @@ func symMerge(data Interface, a, m, b int) {
end := n - start
rotate(data, start, m, end)
- symMerge(data, a, start, mid)
- symMerge(data, mid, end, b)
+ if a < start && start < mid {
+ symMerge(data, a, start, mid)
+ }
+ if mid < end && end < b {
+ symMerge(data, mid, end, b)
+ }
}
// Rotate two consecutives blocks u = data[a:m] and v = data[m:b] in data: