gitee.com/h79/goutils@v1.22.10/common/queue/priority.go (about) 1 package queue 2 3 import "time" 4 5 // Priority 优先级 6 type Priority struct { 7 l []IPriority 8 location *time.Location 9 } 10 11 var _ Queue = (*Priority)(nil) 12 13 func NewPriority() *Priority { 14 return &Priority{location: time.Local} 15 } 16 17 func (pq *Priority) SetLocation(l *time.Location) { 18 pq.location = l 19 } 20 21 // Len returns the Priority length. 22 func (pq *Priority) Len() int { return len(pq.l) } 23 24 func (pq *Priority) Add(elem any) error { 25 return pq.Push(elem) 26 } 27 28 func (pq *Priority) Push(x any) error { 29 p := NewPriorityItem(x, WithUnixNano(pq.location)) 30 index := pq.getInsertIndex(p.PValue(), 0, pq.Len()-1) 31 pq.l = append(pq.l, nil) 32 copy(pq.l[index+1:], pq.l[index:]) 33 34 pq.l[index] = p 35 return nil 36 } 37 38 // Pop implements the heap.Interface.Pop. 39 // Removes and returns element Len() - 1. 40 func (pq *Priority) Pop() any { 41 //old := pq.l 42 //n := len(old) 43 //if n == 0 { 44 // return nil 45 //} 46 //item := old[n-1] 47 //pq.l = old[0 : n-1] 48 old := pq.l 49 item := old[0] 50 pq.l = old[1:] 51 return item.GValue() 52 } 53 54 // Head returns the first item of a Priority without removing it. 55 func (pq *Priority) Head() IPriority { 56 if pq.Empty() { 57 return nil 58 } 59 return pq.l[0] 60 } 61 62 func (pq *Priority) Peek() any { 63 if pq.Empty() { 64 return nil 65 } 66 return pq.l[0].GValue() 67 } 68 69 // Remove removes and returns the element at index i from the Priority. 70 func (pq *Priority) Remove(i int) any { 71 if i < 0 && i >= pq.Len() { 72 return nil 73 } 74 item := pq.l[i] 75 pq.l = append(pq.l[:i], pq.l[i+1:]...) 76 return item.GValue() 77 } 78 79 func (pq *Priority) Empty() bool { 80 return pq.Len() == 0 81 } 82 83 // Find return index -1 not found. 84 func (pq *Priority) Find(fn IndexFunc) (any, int) { 85 for i := range pq.l { 86 if fn(pq.l[i], i) { 87 return pq.l[i], i 88 } 89 } 90 return nil, -1 91 } 92 93 func (pq *Priority) Foreach(fn IndexFunc) { 94 for i := range pq.l { 95 if fn(pq.l[i], i) { 96 return 97 } 98 } 99 } 100 101 func (pq *Priority) getInsertIndex(priority int64, leftIndex, rightIndex int) (index int) { 102 if len(pq.l) == 0 { 103 // 如果当前优先级切片没有元素,则插入的index就是0 104 return 0 105 } 106 107 length := rightIndex - leftIndex 108 if pq.l[leftIndex].PValue() >= priority { 109 // 如果当前切片中最小的元素都超过了插入的优先级,则插入位置应该是最左边 110 return leftIndex 111 } 112 113 if pq.l[rightIndex].PValue() <= priority { 114 // 如果当前切片中最大的元素都没超过插入的优先级,则插入位置应该是最右边 115 return rightIndex + 1 116 } 117 118 if length == 1 && pq.l[leftIndex].PValue() < priority && pq.l[rightIndex].PValue() >= priority { 119 // 如果插入的优先级刚好在仅有的两个优先级之间,则中间的位置就是插入位置 120 return leftIndex + 1 121 } 122 123 middleVal := pq.l[leftIndex+length/2].PValue() 124 125 // 这里用二分法递归的方式,一直寻找正确的插入位置 126 if priority <= middleVal { 127 return pq.getInsertIndex(priority, leftIndex, leftIndex+length/2) 128 } 129 return pq.getInsertIndex(priority, leftIndex+length/2, rightIndex) 130 }