github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/base/bslice/sort.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package bslice 6 7 import ( 8 "github.com/songzhibin97/go-baseutils/base/btype" 9 "math/bits" 10 ) 11 12 // Sort sorts a slice of any ordered type in ascending order. 13 // Sort may fail to sort correctly when sorting slices of floating-point 14 // numbers containing Not-a-number (NaN) values. 15 // Use slices.SortFunc(x, func(a, b float64) bool {return a < b || (math.IsNaN(a) && !math.IsNaN(b))}) 16 // instead if the input may contain NaNs. 17 func Sort[E btype.Ordered](x []E) { 18 n := len(x) 19 pdqsortOrdered(x, 0, n, bits.Len(uint(n))) 20 } 21 22 // SortFunc sorts the slice x in ascending order as determined by the less function. 23 // This sort is not guaranteed to be stable. 24 // 25 // SortFunc requires that less is a strict weak ordering. 26 // See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings. 27 func SortFunc[E any](x []E, less func(a, b E) bool) { 28 n := len(x) 29 pdqsortLessFunc(x, 0, n, bits.Len(uint(n)), less) 30 } 31 32 // SortStableFunc sorts the slice x while keeping the original order of equal 33 // elements, using less to compare elements. 34 func SortStableFunc[E any](x []E, less func(a, b E) bool) { 35 stableLessFunc(x, len(x), less) 36 } 37 38 // IsSorted reports whether x is sorted in ascending order. 39 func IsSorted[E btype.Ordered](x []E) bool { 40 for i := len(x) - 1; i > 0; i-- { 41 if x[i] < x[i-1] { 42 return false 43 } 44 } 45 return true 46 } 47 48 // IsSortedFunc reports whether x is sorted in ascending order, with less as the 49 // comparison function. 50 func IsSortedFunc[E any](x []E, less func(a, b E) bool) bool { 51 for i := len(x) - 1; i > 0; i-- { 52 if less(x[i], x[i-1]) { 53 return false 54 } 55 } 56 return true 57 } 58 59 // BinarySearch searches for target in a sorted slice and returns the position 60 // where target is found, or the position where target would appear in the 61 // sort order; it also returns a bool saying whether the target is really found 62 // in the slice. The slice must be sorted in increasing order. 63 func BinarySearch[E btype.Ordered](x []E, target E) (int, bool) { 64 // Inlining is faster than calling BinarySearchFunc with a lambda. 65 n := len(x) 66 // Define x[-1] < target and x[n] >= target. 67 // Invariant: x[i-1] < target, x[j] >= target. 68 i, j := 0, n 69 for i < j { 70 h := int(uint(i+j) >> 1) // avoid overflow when computing h 71 // i ≤ h < j 72 if x[h] < target { 73 i = h + 1 // preserves x[i-1] < target 74 } else { 75 j = h // preserves x[j] >= target 76 } 77 } 78 // i == j, x[i-1] < target, and x[j] (= x[i]) >= target => answer is i. 79 return i, i < n && x[i] == target 80 } 81 82 // BinarySearchFunc works like BinarySearch, but uses a custom comparison 83 // function. The slice must be sorted in increasing order, where "increasing" 84 // is defined by cmp. cmp should return 0 if the slice element matches 85 // the target, a negative number if the slice element precedes the target, 86 // or a positive number if the slice element follows the target. 87 // cmp must implement the same ordering as the slice, such that if 88 // cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice. 89 func BinarySearchFunc[E, T any](x []E, target T, cmp func(E, T) int) (int, bool) { 90 n := len(x) 91 // Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 . 92 // Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0. 93 i, j := 0, n 94 for i < j { 95 h := int(uint(i+j) >> 1) // avoid overflow when computing h 96 // i ≤ h < j 97 if cmp(x[h], target) < 0 { 98 i = h + 1 // preserves cmp(x[i - 1], target) < 0 99 } else { 100 j = h // preserves cmp(x[j], target) >= 0 101 } 102 } 103 // i == j, cmp(x[i-1], target) < 0, and cmp(x[j], target) (= cmp(x[i], target)) >= 0 => answer is i. 104 return i, i < n && cmp(x[i], target) == 0 105 } 106 107 type sortedHint int // hint for pdqsort when choosing the pivot 108 109 const ( 110 unknownHint sortedHint = iota 111 increasingHint 112 decreasingHint 113 ) 114 115 // xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf 116 type xorshift uint64 117 118 func (r *xorshift) Next() uint64 { 119 *r ^= *r << 13 120 *r ^= *r >> 17 121 *r ^= *r << 5 122 return uint64(*r) 123 } 124 125 func nextPowerOfTwo(length int) uint { 126 return 1 << bits.Len(uint(length)) 127 }