github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/structure/trees/binaryheap/binaryheap_test.go (about) 1 package binaryheap 2 3 import ( 4 "encoding/json" 5 "math/rand" 6 "strings" 7 "testing" 8 ) 9 10 func TestBinaryHeapPush(t *testing.T) { 11 heap := NewWithIntComparator() 12 13 if actualValue := heap.Empty(); actualValue != true { 14 t.Errorf("Got %v expected %v", actualValue, true) 15 } 16 17 heap.Push(3) 18 heap.Push(2) 19 heap.Push(1) 20 21 if actualValue := heap.Values(); actualValue[0] != 1 || actualValue[1] != 2 || actualValue[2] != 3 { 22 t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") 23 } 24 if actualValue := heap.Empty(); actualValue != false { 25 t.Errorf("Got %v expected %v", actualValue, false) 26 } 27 if actualValue := heap.Size(); actualValue != 3 { 28 t.Errorf("Got %v expected %v", actualValue, 3) 29 } 30 if actualValue, ok := heap.Peek(); actualValue != 1 || !ok { 31 t.Errorf("Got %v expected %v", actualValue, 1) 32 } 33 } 34 35 func TestBinaryHeapPushBulk(t *testing.T) { 36 heap := NewWithIntComparator() 37 38 heap.Push(15, 20, 3, 1, 2) 39 40 if actualValue := heap.Values(); actualValue[0] != 1 || actualValue[1] != 2 || actualValue[2] != 3 { 41 t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") 42 } 43 if actualValue, ok := heap.Pop(); actualValue != 1 || !ok { 44 t.Errorf("Got %v expected %v", actualValue, 1) 45 } 46 } 47 48 func TestBinaryHeapPop(t *testing.T) { 49 heap := NewWithIntComparator() 50 51 if actualValue := heap.Empty(); actualValue != true { 52 t.Errorf("Got %v expected %v", actualValue, true) 53 } 54 55 heap.Push(3) 56 heap.Push(2) 57 heap.Push(1) 58 heap.Pop() 59 60 if actualValue, ok := heap.Peek(); actualValue != 2 || !ok { 61 t.Errorf("Got %v expected %v", actualValue, 2) 62 } 63 if actualValue, ok := heap.Pop(); actualValue != 2 || !ok { 64 t.Errorf("Got %v expected %v", actualValue, 2) 65 } 66 if actualValue, ok := heap.Pop(); actualValue != 3 || !ok { 67 t.Errorf("Got %v expected %v", actualValue, 3) 68 } 69 if actualValue, ok := heap.Pop(); actualValue != 0 || ok { 70 t.Errorf("Got %v expected %v", actualValue, nil) 71 } 72 if actualValue := heap.Empty(); actualValue != true { 73 t.Errorf("Got %v expected %v", actualValue, true) 74 } 75 if actualValue := heap.Values(); len(actualValue) != 0 { 76 t.Errorf("Got %v expected %v", actualValue, "[]") 77 } 78 } 79 80 func TestBinaryHeapRandom(t *testing.T) { 81 heap := NewWithIntComparator() 82 83 rand.Seed(3) 84 for i := 0; i < 10000; i++ { 85 r := int(rand.Int31n(30)) 86 heap.Push(r) 87 } 88 89 prev, _ := heap.Pop() 90 for !heap.Empty() { 91 curr, _ := heap.Pop() 92 if prev > curr { 93 t.Errorf("Heap property invalidated. prev: %v current: %v", prev, curr) 94 } 95 prev = curr 96 } 97 } 98 99 func TestBinaryHeapIteratorOnEmpty(t *testing.T) { 100 heap := NewWithIntComparator() 101 it := heap.Iterator() 102 for it.Next() { 103 t.Errorf("Shouldn't iterate on empty heap") 104 } 105 } 106 107 func TestBinaryHeapIteratorNext(t *testing.T) { 108 heap := NewWithIntComparator() 109 heap.Push(3) 110 heap.Push(2) 111 heap.Push(1) 112 113 it := heap.Iterator() 114 count := 0 115 for it.Next() { 116 count++ 117 index := it.Index() 118 value := it.Value() 119 switch index { 120 case 0: 121 if actualValue, expectedValue := value, 1; actualValue != expectedValue { 122 t.Errorf("Got %v expected %v", actualValue, expectedValue) 123 } 124 case 1: 125 if actualValue, expectedValue := value, 2; actualValue != expectedValue { 126 t.Errorf("Got %v expected %v", actualValue, expectedValue) 127 } 128 case 2: 129 if actualValue, expectedValue := value, 3; actualValue != expectedValue { 130 t.Errorf("Got %v expected %v", actualValue, expectedValue) 131 } 132 default: 133 t.Errorf("Too many") 134 } 135 if actualValue, expectedValue := index, count-1; actualValue != expectedValue { 136 t.Errorf("Got %v expected %v", actualValue, expectedValue) 137 } 138 } 139 if actualValue, expectedValue := count, 3; actualValue != expectedValue { 140 t.Errorf("Got %v expected %v", actualValue, expectedValue) 141 } 142 } 143 144 func TestBinaryHeapIteratorPrev(t *testing.T) { 145 heap := NewWithIntComparator() 146 heap.Push(3) 147 heap.Push(2) 148 heap.Push(1) 149 150 it := heap.Iterator() 151 for it.Next() { 152 } 153 count := 0 154 for it.Prev() { 155 count++ 156 index := it.Index() 157 value := it.Value() 158 switch index { 159 case 0: 160 if actualValue, expectedValue := value, 1; actualValue != expectedValue { 161 t.Errorf("Got %v expected %v", actualValue, expectedValue) 162 } 163 case 1: 164 if actualValue, expectedValue := value, 2; actualValue != expectedValue { 165 t.Errorf("Got %v expected %v", actualValue, expectedValue) 166 } 167 case 2: 168 if actualValue, expectedValue := value, 3; actualValue != expectedValue { 169 t.Errorf("Got %v expected %v", actualValue, expectedValue) 170 } 171 default: 172 t.Errorf("Too many") 173 } 174 if actualValue, expectedValue := index, 3-count; actualValue != expectedValue { 175 t.Errorf("Got %v expected %v", actualValue, expectedValue) 176 } 177 } 178 if actualValue, expectedValue := count, 3; actualValue != expectedValue { 179 t.Errorf("Got %v expected %v", actualValue, expectedValue) 180 } 181 } 182 183 func TestBinaryHeapIteratorBegin(t *testing.T) { 184 heap := NewWithIntComparator() 185 it := heap.Iterator() 186 it.Begin() 187 heap.Push(2) 188 heap.Push(3) 189 heap.Push(1) 190 for it.Next() { 191 } 192 it.Begin() 193 it.Next() 194 if index, value := it.Index(), it.Value(); index != 0 || value != 1 { 195 t.Errorf("Got %v,%v expected %v,%v", index, value, 0, 1) 196 } 197 } 198 199 func TestBinaryHeapIteratorEnd(t *testing.T) { 200 heap := NewWithIntComparator() 201 it := heap.Iterator() 202 203 if index := it.Index(); index != -1 { 204 t.Errorf("Got %v expected %v", index, -1) 205 } 206 207 it.End() 208 if index := it.Index(); index != 0 { 209 t.Errorf("Got %v expected %v", index, 0) 210 } 211 212 heap.Push(3) 213 heap.Push(2) 214 heap.Push(1) 215 it.End() 216 if index := it.Index(); index != heap.Size() { 217 t.Errorf("Got %v expected %v", index, heap.Size()) 218 } 219 220 it.Prev() 221 if index, value := it.Index(), it.Value(); index != heap.Size()-1 || value != 3 { 222 t.Errorf("Got %v,%v expected %v,%v", index, value, heap.Size()-1, 3) 223 } 224 } 225 226 func TestBinaryHeapIteratorFirst(t *testing.T) { 227 heap := NewWithIntComparator() 228 it := heap.Iterator() 229 if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { 230 t.Errorf("Got %v expected %v", actualValue, expectedValue) 231 } 232 heap.Push(3) 233 heap.Push(2) 234 heap.Push(1) 235 if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { 236 t.Errorf("Got %v expected %v", actualValue, expectedValue) 237 } 238 if index, value := it.Index(), it.Value(); index != 0 || value != 1 { 239 t.Errorf("Got %v,%v expected %v,%v", index, value, 0, 1) 240 } 241 } 242 243 func TestBinaryHeapIteratorLast(t *testing.T) { 244 tree := NewWithIntComparator() 245 it := tree.Iterator() 246 if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { 247 t.Errorf("Got %v expected %v", actualValue, expectedValue) 248 } 249 tree.Push(2) 250 tree.Push(3) 251 tree.Push(1) 252 if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { 253 t.Errorf("Got %v expected %v", actualValue, expectedValue) 254 } 255 if index, value := it.Index(), it.Value(); index != 2 || value != 3 { 256 t.Errorf("Got %v,%v expected %v,%v", index, value, 2, 3) 257 } 258 } 259 260 func TestBinaryHeapIteratorNextTo(t *testing.T) { 261 // Sample seek function, i.e. string starting with "b" 262 seek := func(index int, value string) bool { 263 return strings.HasSuffix(value, "b") 264 } 265 266 // NextTo (empty) 267 { 268 tree := NewWithStringComparator() 269 it := tree.Iterator() 270 for it.NextTo(seek) { 271 t.Errorf("Shouldn't iterate on empty list") 272 } 273 } 274 275 // NextTo (not found) 276 { 277 tree := NewWithStringComparator() 278 tree.Push("xx") 279 tree.Push("yy") 280 it := tree.Iterator() 281 for it.NextTo(seek) { 282 t.Errorf("Shouldn't iterate on empty list") 283 } 284 } 285 286 // NextTo (found) 287 { 288 tree := NewWithStringComparator() 289 tree.Push("aa") 290 tree.Push("bb") 291 tree.Push("cc") 292 it := tree.Iterator() 293 it.Begin() 294 if !it.NextTo(seek) { 295 t.Errorf("Shouldn't iterate on empty list") 296 } 297 if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { 298 t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") 299 } 300 if !it.Next() { 301 t.Errorf("Should go to first element") 302 } 303 if index, value := it.Index(), it.Value(); index != 2 || value != "cc" { 304 t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") 305 } 306 if it.Next() { 307 t.Errorf("Should not go past last element") 308 } 309 } 310 } 311 312 func TestBinaryHeapIteratorPrevTo(t *testing.T) { 313 // Sample seek function, i.e. string starting with "b" 314 seek := func(index int, value string) bool { 315 return strings.HasSuffix(value, "b") 316 } 317 318 // PrevTo (empty) 319 { 320 tree := NewWithStringComparator() 321 it := tree.Iterator() 322 it.End() 323 for it.PrevTo(seek) { 324 t.Errorf("Shouldn't iterate on empty list") 325 } 326 } 327 328 // PrevTo (not found) 329 { 330 tree := NewWithStringComparator() 331 tree.Push("xx") 332 tree.Push("yy") 333 it := tree.Iterator() 334 it.End() 335 for it.PrevTo(seek) { 336 t.Errorf("Shouldn't iterate on empty list") 337 } 338 } 339 340 // PrevTo (found) 341 { 342 tree := NewWithStringComparator() 343 tree.Push("aa") 344 tree.Push("bb") 345 tree.Push("cc") 346 it := tree.Iterator() 347 it.End() 348 if !it.PrevTo(seek) { 349 t.Errorf("Shouldn't iterate on empty list") 350 } 351 if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { 352 t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") 353 } 354 if !it.Prev() { 355 t.Errorf("Should go to first element") 356 } 357 if index, value := it.Index(), it.Value(); index != 0 || value != "aa" { 358 t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") 359 } 360 if it.Prev() { 361 t.Errorf("Should not go before first element") 362 } 363 } 364 } 365 366 func TestBinaryHeapSerialization(t *testing.T) { 367 heap := NewWithStringComparator() 368 369 heap.Push("c") 370 heap.Push("b") 371 heap.Push("a") 372 373 var err error 374 assert := func() { 375 if actualValue := heap.Values(); actualValue[0] != "a" || actualValue[1] != "b" || actualValue[2] != "c" { 376 t.Errorf("Got %v expected %v", actualValue, "[1,3,2]") 377 } 378 if actualValue := heap.Size(); actualValue != 3 { 379 t.Errorf("Got %v expected %v", actualValue, 3) 380 } 381 if actualValue, ok := heap.Peek(); actualValue != "a" || !ok { 382 t.Errorf("Got %v expected %v", actualValue, "a") 383 } 384 if err != nil { 385 t.Errorf("Got error %v", err) 386 } 387 } 388 389 assert() 390 391 bytes, err := heap.MarshalJSON() 392 assert() 393 394 err = heap.UnmarshalJSON(bytes) 395 assert() 396 397 bytes, err = json.Marshal([]interface{}{"a", "b", "c", heap}) 398 if err != nil { 399 t.Errorf("Got error %v", err) 400 } 401 402 err = json.Unmarshal([]byte(`["1","2","3"]`), &heap) 403 if err != nil { 404 t.Errorf("Got error %v", err) 405 } 406 } 407 408 func TestBTreeString(t *testing.T) { 409 c := NewWithIntComparator() 410 c.Push(1) 411 if !strings.HasPrefix(c.String(), "BinaryHeap") { 412 t.Errorf("String should start with container name") 413 } 414 } 415 416 func benchmarkPush[E int](b *testing.B, heap *Heap[E], size int) { 417 for i := 0; i < b.N; i++ { 418 for n := 0; n < size; n++ { 419 heap.Push(E(n)) 420 } 421 } 422 } 423 424 func benchmarkPop[E int](b *testing.B, heap *Heap[E], size int) { 425 for i := 0; i < b.N; i++ { 426 for n := 0; n < size; n++ { 427 heap.Pop() 428 } 429 } 430 } 431 432 func BenchmarkBinaryHeapPop100(b *testing.B) { 433 b.StopTimer() 434 size := 100 435 heap := NewWithIntComparator() 436 for n := 0; n < size; n++ { 437 heap.Push(n) 438 } 439 b.StartTimer() 440 benchmarkPop(b, heap, size) 441 } 442 443 func BenchmarkBinaryHeapPop1000(b *testing.B) { 444 b.StopTimer() 445 size := 1000 446 heap := NewWithIntComparator() 447 for n := 0; n < size; n++ { 448 heap.Push(n) 449 } 450 b.StartTimer() 451 benchmarkPop(b, heap, size) 452 } 453 454 func BenchmarkBinaryHeapPop10000(b *testing.B) { 455 b.StopTimer() 456 size := 10000 457 heap := NewWithIntComparator() 458 for n := 0; n < size; n++ { 459 heap.Push(n) 460 } 461 b.StartTimer() 462 benchmarkPop(b, heap, size) 463 } 464 465 func BenchmarkBinaryHeapPop100000(b *testing.B) { 466 b.StopTimer() 467 size := 100000 468 heap := NewWithIntComparator() 469 for n := 0; n < size; n++ { 470 heap.Push(n) 471 } 472 b.StartTimer() 473 benchmarkPop(b, heap, size) 474 } 475 476 func BenchmarkBinaryHeapPush100(b *testing.B) { 477 b.StopTimer() 478 size := 100 479 heap := NewWithIntComparator() 480 b.StartTimer() 481 benchmarkPush(b, heap, size) 482 } 483 484 func BenchmarkBinaryHeapPush1000(b *testing.B) { 485 b.StopTimer() 486 size := 1000 487 heap := NewWithIntComparator() 488 for n := 0; n < size; n++ { 489 heap.Push(n) 490 } 491 b.StartTimer() 492 benchmarkPush(b, heap, size) 493 } 494 495 func BenchmarkBinaryHeapPush10000(b *testing.B) { 496 b.StopTimer() 497 size := 10000 498 heap := NewWithIntComparator() 499 for n := 0; n < size; n++ { 500 heap.Push(n) 501 } 502 b.StartTimer() 503 benchmarkPush(b, heap, size) 504 } 505 506 func BenchmarkBinaryHeapPush100000(b *testing.B) { 507 b.StopTimer() 508 size := 100000 509 heap := NewWithIntComparator() 510 for n := 0; n < size; n++ { 511 heap.Push(n) 512 } 513 b.StartTimer() 514 benchmarkPush(b, heap, size) 515 }