github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/container/heap/heap_test.go (about) 1 // Copyright 2009 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 heap 6 7 import ( 8 "math/rand" 9 "testing" 10 ) 11 12 type myHeap []int 13 14 func (h *myHeap) Less(i, j int) bool { 15 return (*h)[i] < (*h)[j] 16 } 17 18 func (h *myHeap) Swap(i, j int) { 19 (*h)[i], (*h)[j] = (*h)[j], (*h)[i] 20 } 21 22 func (h *myHeap) Len() int { 23 return len(*h) 24 } 25 26 // push 和 pop 都是操作的最后一个元素 27 func (h *myHeap) Pop() (v interface{}) { 28 // Pop 删除并返回最后一个元素, 并且更新heap 为前h.Len()-1的元素数组 29 *h, v = (*h)[:h.Len()-1], (*h)[h.Len()-1] 30 return 31 } 32 33 // Push 是从数组后面添加元素 34 func (h *myHeap) Push(v interface{}) { 35 *h = append(*h, v.(int)) 36 } 37 38 func (h myHeap) verify(t *testing.T, i int) { 39 t.Helper() 40 n := h.Len() 41 j1 := 2*i + 1 42 j2 := 2*i + 2 43 if j1 < n { // 存在左子树节点 44 if h.Less(j1, i) { // 如果左节点小于i节点,表示 子节点小于父节点值, 不满足最小堆 45 t.Errorf("heap invariant invalidated [%d] = %d > [%d] = %d", i, h[i], j1, h[j1]) 46 return 47 } 48 h.verify(t, j1) 49 } 50 if j2 < n { // 存在右子树节点 51 if h.Less(j2, i) { 52 t.Errorf("heap invariant invalidated [%d] = %d > [%d] = %d", i, h[i], j1, h[j2]) 53 return 54 } 55 h.verify(t, j2) 56 } 57 } 58 59 func TestInit0(t *testing.T) { 60 h := new(myHeap) // 初始化 61 // 装填数据 62 for i := 20; i > 0; i-- { 63 h.Push(0) // all elements are the same 64 } 65 Init(h) // 构建最小堆 66 h.verify(t, 0) // 验证最小堆 67 68 // 出去值 并验证最小堆 69 for i := 1; h.Len() > 0; i++ { 70 x := Pop(h).(int) 71 h.verify(t, 0) 72 if x != 0 { 73 t.Errorf("%d.th pop got %d; want %d", i, x, 0) 74 } 75 } 76 } 77 78 func TestInit1(t *testing.T) { 79 h := new(myHeap) 80 for i := 20; i > 0; i-- { 81 h.Push(i) // all elements are different 82 } 83 Init(h) 84 h.verify(t, 0) 85 86 for i := 1; h.Len() > 0; i++ { 87 x := Pop(h).(int) 88 h.verify(t, 0) 89 if x != i { 90 t.Errorf("%d.th pop got %d; want %d", i, x, i) 91 } 92 } 93 } 94 95 func Test(t *testing.T) { 96 h := new(myHeap) // 初始化一个空数组 97 h.verify(t, 0) // 堆化验证 98 99 for i := 20; i > 10; i-- { 100 h.Push(i) 101 } 102 Init(h) 103 h.verify(t, 0) 104 105 for i := 10; i > 0; i-- { 106 Push(h, i) 107 h.verify(t, 0) 108 } 109 110 for i := 1; h.Len() > 0; i++ { 111 x := Pop(h).(int) 112 if i < 20 { 113 Push(h, 20+i) 114 } 115 h.verify(t, 0) 116 if x != i { 117 t.Errorf("%d.th pop got %d; want %d", i, x, i) 118 } 119 } 120 } 121 122 func TestRemove0(t *testing.T) { 123 h := new(myHeap) 124 for i := 0; i < 10; i++ { 125 h.Push(i) 126 } 127 h.verify(t, 0) 128 129 for h.Len() > 0 { 130 i := h.Len() - 1 131 x := Remove(h, i).(int) // 删除第i位 堆化调整最小堆 132 if x != i { 133 t.Errorf("Remove(%d) got %d; want %d", i, x, i) 134 } 135 h.verify(t, 0) 136 } 137 } 138 139 func TestRemove1(t *testing.T) { 140 h := new(myHeap) 141 for i := 0; i < 10; i++ { 142 h.Push(i) 143 } 144 h.verify(t, 0) 145 146 for i := 0; h.Len() > 0; i++ { 147 x := Remove(h, 0).(int) // 每次都是删除堆顶调整最小堆 148 if x != i { 149 t.Errorf("Remove(0) got %d; want %d", x, i) 150 } 151 h.verify(t, 0) 152 } 153 } 154 155 func TestRemove2(t *testing.T) { 156 N := 10 157 158 h := new(myHeap) 159 for i := 0; i < N; i++ { 160 h.Push(i) 161 } 162 h.verify(t, 0) 163 164 m := make(map[int]bool) 165 for h.Len() > 0 { 166 m[Remove(h, (h.Len()-1)/2).(int)] = true 167 h.verify(t, 0) 168 } 169 170 if len(m) != N { 171 t.Errorf("len(m) = %d; want %d", len(m), N) 172 } 173 for i := 0; i < len(m); i++ { 174 if !m[i] { 175 t.Errorf("m[%d] doesn't exist", i) 176 } 177 } 178 } 179 180 func BenchmarkDup(b *testing.B) { 181 const n = 10000 182 h := make(myHeap, 0, n) 183 for i := 0; i < b.N; i++ { 184 for j := 0; j < n; j++ { 185 Push(&h, 0) // all elements are the same 186 } 187 for h.Len() > 0 { 188 Pop(&h) 189 } 190 } 191 } 192 193 func TestFix(t *testing.T) { // 测试修复值之后 堆化调整最小堆, 这个比删除这个值 再插入一个新元素效率更高 194 h := new(myHeap) 195 h.verify(t, 0) 196 197 for i := 200; i > 0; i -= 10 { 198 Push(h, i) 199 } 200 h.verify(t, 0) 201 202 if (*h)[0] != 10 { 203 t.Fatalf("Expected head to be 10, was %d", (*h)[0]) 204 } 205 (*h)[0] = 210 // 修改堆顶元素 206 Fix(h, 0) // 调整堆顶0 位置, 堆化最小堆 207 h.verify(t, 0) 208 209 for i := 100; i > 0; i-- { 210 elem := rand.Intn(h.Len()) // 随机调整,随机堆化并验证 211 if i&1 == 0 { 212 (*h)[elem] *= 2 213 } else { 214 (*h)[elem] /= 2 215 } 216 Fix(h, elem) 217 h.verify(t, 0) 218 } 219 }