github.com/searKing/golang/go@v1.2.74/exp/slices/sort.go (about) 1 // Copyright 2022 The searKing Author. 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 slices 6 7 import ( 8 "container/heap" 9 "sort" 10 11 sort_ "github.com/searKing/golang/go/sort" 12 "golang.org/x/exp/constraints" 13 ) 14 15 // LinearSearch searches for target in a sorted slice and returns the position 16 // where target is found, or the position where target would appear in the 17 // sort order; it also returns a bool saying whether the target is really found 18 // in the slice. The slice must be sorted in increasing order. 19 // Note: Binary-search was compared using the benchmarks. The following 20 // code is equivalent to the linear search above: 21 // 22 // pos := sort.Search(len(x), func(i int) bool { 23 // return target < x[i] 24 // }) 25 // 26 // The binary search wins for very large boundary sets, but 27 // the linear search performs better up through arrays between 28 // 256 and 512 elements, so we continue to prefer linear search. 29 func LinearSearch[S ~[]E, E constraints.Ordered](x S, target E) (int, bool) { 30 // search returns the leftmost position where f returns true, or len(x) if f 31 // returns false for all x. This is the insertion position for target in x, 32 // and could point to an element that's either == target or not. 33 pos := search(len(x), func(i int) bool { 34 return x[i] >= target 35 }) 36 if pos >= len(x) || x[pos] != target { 37 return pos, false 38 } else { 39 return pos, true 40 } 41 } 42 43 // LinearSearchFunc works like LinearSearch, but uses a custom comparison 44 // function. The slice must be sorted in increasing order, where "increasing" is 45 // defined by cmp. cmp(a, b) is expected to return an integer comparing the two 46 // parameters: 0 if a == b, a negative number if a < b and a positive number if 47 // a > b. 48 func LinearSearchFunc[S ~[]E, E any](x S, target E, cmp func(E, E) int) (int, bool) { 49 pos := search(len(x), func(i int) bool { return cmp(x[i], target) >= 0 }) 50 if pos >= len(x) || cmp(x[pos], target) != 0 { 51 return pos, false 52 } else { 53 return pos, true 54 } 55 } 56 57 func search(n int, f func(int) bool) int { 58 pos := n 59 for i := 0; i < n; i++ { 60 if f(i) { 61 return i // preserves f(i) == true 62 } 63 } 64 return pos 65 } 66 67 // PartialSort rearranges elements such that the range [0, m) 68 // contains the sorted m smallest elements in the range [first, data.Len). 69 // The order of equal elements is not guaranteed to be preserved. 70 // The order of the remaining elements in the range [m, data.Len) is unspecified. 71 // PartialSort modifies the contents of the slice s; it does not create a new slice. 72 func PartialSort[S ~[]E, E constraints.Ordered](s S, k int) { 73 if s == nil { 74 return 75 } 76 77 if k <= 0 { 78 return 79 } 80 if k >= len(s) { 81 sort.Sort(SortSlice[E](s)) 82 return 83 } 84 85 var ss = make(S, k) 86 copy(ss, s[:k]) 87 h := MaxHeap[E](ss) 88 heap.Init(&h) 89 for i, v := range s[k:] { 90 heap.Push(&h, v) 91 vv := heap.Pop(&h).(E) 92 s[i+k] = vv 93 } 94 95 for h.Len() > 0 { 96 s[h.Len()-1] = heap.Pop(&h).(E) 97 } 98 return 99 } 100 101 func PartialSortFunc[S ~[]E, E any](s S, k int, cmp func(E, E) int) { 102 if s == nil { 103 return 104 } 105 106 if k <= 0 { 107 return 108 } 109 110 if k >= len(s) { 111 k = len(s) 112 } 113 114 var ss = make(S, k) 115 copy(ss, s[:k]) 116 117 if k <= 0 { 118 return 119 } 120 // MaxHeap 121 h := NewHeapFunc(ss, func(a E, b E) int { 122 if cmp == nil { 123 return 0 124 } 125 return -cmp(a, b) 126 }) 127 heap.Init(h) 128 for i, v := range s[k:] { 129 heap.Push(h, v) 130 vv := heap.Pop(h).(E) 131 s[i+k] = vv 132 } 133 134 for h.Len() > 0 { 135 s[h.Len()-1] = heap.Pop(h).(E) 136 } 137 return 138 } 139 140 // IsPartialSorted reports whether data[:k] is partial sorted, as top k of data[:]. 141 func IsPartialSorted[S ~[]E, E constraints.Ordered](s S, k int) bool { 142 return sort_.IsPartialSorted(SortSlice[E](s), k) 143 } 144 145 // Convenience types for common cases 146 147 // SortSlice attaches the methods of Interface to []E, sorting in increasing order. 148 type SortSlice[E constraints.Ordered] []E 149 150 func (x SortSlice[E]) Len() int { return len(x) } 151 152 // Less reports whether x[i] should be ordered before x[j], as required by the sort Interface. 153 // Note that floating-point comparison by itself is not a transitive relation: it does not 154 // report a consistent ordering for not-a-number (NaN) values. 155 // This implementation of Less places NaN values before any others, by using: 156 // 157 // x[i] < x[j] || (math.IsNaN(x[i]) && !math.IsNaN(x[j])) 158 func (x SortSlice[E]) Less(i, j int) bool { return x[i] < x[j] || (isNaN(x[i]) && !isNaN(x[j])) } 159 func (x SortSlice[E]) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 160 161 // Sort is a convenience method: x.Sort() calls Sort(x). 162 func (x SortSlice[E]) Sort() { sort.Sort(x) } 163 164 // isNaN is a copy of math.IsNaN to avoid a dependency on the math package. 165 func isNaN[E constraints.Ordered](f E) bool { 166 return f != f 167 }