github.com/biogo/store@v0.0.0-20201120204734-aad293a2328f/llrb/llrb_test.go (about) 1 // Copyright ©2012 The bíogo 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 llrb 6 7 import ( 8 "flag" 9 "fmt" 10 "math/rand" 11 "os" 12 "sort" 13 "strings" 14 "testing" 15 "unsafe" 16 17 "gopkg.in/check.v1" 18 ) 19 20 var ( 21 printTree = flag.Bool("trees", false, "Print failing tree in Newick format.") 22 genDot = flag.Bool("dot", false, "Generate dot code for failing trees.") 23 dotLimit = flag.Int("dotmax", 100, "Maximum size for tree output for dot format.") 24 ) 25 26 // Integrity checks - translated from http://www.cs.princeton.edu/~rs/talks/LLRB/Java/RedBlackBST.java 27 28 // Is this tree a BST? 29 func (t *Tree) isBST() bool { 30 if t == nil { 31 return true 32 } 33 return t.Root.isBST(t.Min(), t.Max()) 34 } 35 36 // Are all the values in the BST rooted at x between min and max, 37 // and does the same property hold for both subtrees? 38 func (n *Node) isBST(min, max Comparable) bool { 39 if n == nil { 40 return true 41 } 42 if n.Elem.Compare(min) < 0 || n.Elem.Compare(max) > 0 { 43 return false 44 } 45 return n.Left.isBST(min, n.Elem) && n.Right.isBST(n.Elem, max) 46 } 47 48 // Test BU and TD234 invariants. 49 func (t *Tree) is23_234() bool { 50 if t == nil { 51 return true 52 } 53 return t.Root.is23_234() 54 } 55 func (n *Node) is23_234() bool { 56 if n == nil { 57 return true 58 } 59 if Mode == BU23 { 60 // If the node has two children, only one of them may be red. 61 // The other must be black... 62 if (n.Left != nil) && (n.Right != nil) { 63 if n.Left.color() == Red && n.Right.color() == Red { 64 return false 65 } 66 } 67 // and the red node should really should be the left one. 68 if n.Right.color() == Red { 69 return false 70 } 71 } else if Mode == TD234 { 72 // This test is altered from that shown in the java since the trees 73 // shown in the paper do not conform to the test as it existed and the 74 // current situation does not break the 2-3-4 definition of the LLRB. 75 if n.Right.color() == Red && n.Left.color() == Black { 76 return false 77 } 78 } else { 79 panic("cannot reach") 80 } 81 if n.color() == Red && n.Left.color() == Red { 82 return false 83 } 84 return n.Left.is23_234() && n.Right.is23_234() 85 } 86 87 // Do all paths from root to leaf have same number of black edges? 88 func (t *Tree) isBalanced() bool { 89 if t == nil { 90 return true 91 } 92 var black int // number of black links on path from root to min 93 for x := t.Root; x != nil; x = x.Left { 94 if x.color() == Black { 95 black++ 96 } 97 } 98 return t.Root.isBalanced(black) 99 } 100 101 // Does every path from the root to a leaf have the given number 102 // of black links? 103 func (n *Node) isBalanced(black int) bool { 104 if n == nil && black == 0 { 105 return true 106 } else if n == nil && black != 0 { 107 return false 108 } 109 if n.color() == Black { 110 black-- 111 } 112 return n.Left.isBalanced(black) && n.Right.isBalanced(black) 113 } 114 115 // Test helpers 116 117 type compRune rune 118 119 func (cr compRune) Compare(r Comparable) int { 120 return int(cr) - int(r.(compRune)) 121 } 122 123 type compInt int 124 125 func (ci compInt) Compare(i Comparable) (c int) { 126 switch i := i.(type) { 127 case compIntUpper: 128 c = int(ci) - int(i) 129 case compInt: 130 c = int(ci) - int(i) 131 } 132 return c 133 } 134 135 type compIntUpper int 136 137 func (ci compIntUpper) Compare(i Comparable) (c int) { 138 switch i := i.(type) { 139 case compIntUpper: 140 c = int(ci) - int(i) 141 case compInt: 142 c = int(ci) - int(i) 143 } 144 if c == 0 { 145 return 1 146 } 147 return c 148 } 149 150 type Reverse struct { 151 sort.Interface 152 } 153 154 func (r Reverse) Less(i, j int) bool { return r.Interface.Less(j, i) } 155 156 type compInts []compInt 157 158 func (c compInts) Len() int { return len(c) } 159 func (c compInts) Less(i, j int) bool { return c[i].Compare(c[j]) < 0 } 160 func (c compInts) Swap(i, j int) { c[i], c[j] = c[j], c[i] } 161 162 // Build a tree from a simplified Newick format returning the root node. 163 // Single letter node names only, no error checking and all nodes are full or leaf. 164 func makeTree(desc string) (n *Node) { 165 var build func([]rune) (*Node, int) 166 build = func(desc []rune) (cn *Node, i int) { 167 if len(desc) == 0 || desc[0] == ';' { 168 return nil, 0 169 } 170 171 var c int 172 cn = &Node{} 173 for { 174 b := desc[i] 175 i++ 176 if b == '(' { 177 cn.Left, c = build(desc[i:]) 178 i += c 179 continue 180 } 181 if b == ',' { 182 cn.Right, c = build(desc[i:]) 183 i += c 184 continue 185 } 186 if b == ')' { 187 if cn.Left == nil && cn.Right == nil { 188 return nil, i 189 } 190 continue 191 } 192 if b != ';' { 193 cn.Elem = compRune(b) 194 } 195 return cn, i 196 } 197 198 panic("cannot reach") 199 } 200 201 n, _ = build([]rune(desc)) 202 if n.Left == nil && n.Right == nil { 203 n = nil 204 } 205 206 return 207 } 208 209 // Return a Newick format description of a tree defined by a node 210 func describeTree(n *Node, char, color bool) string { 211 s := []rune(nil) 212 213 var follow func(*Node) 214 follow = func(n *Node) { 215 children := n.Left != nil || n.Right != nil 216 if children { 217 s = append(s, '(') 218 } 219 if n.Left != nil { 220 follow(n.Left) 221 } 222 if children { 223 s = append(s, ',') 224 } 225 if n.Right != nil { 226 follow(n.Right) 227 } 228 if children { 229 s = append(s, ')') 230 } 231 if n.Elem != nil { 232 if char { 233 s = append(s, rune(n.Elem.(compRune))) 234 } else { 235 s = append(s, []rune(fmt.Sprintf("%d", n.Elem))...) 236 } 237 if color { 238 s = append(s, []rune(fmt.Sprintf(" %v", n.color()))...) 239 } 240 } 241 } 242 if n == nil { 243 s = []rune("()") 244 } else { 245 follow(n) 246 } 247 s = append(s, ';') 248 249 return string(s) 250 } 251 252 // Tests 253 func Test(t *testing.T) { check.TestingT(t) } 254 255 type S struct{} 256 257 var _ = check.Suite(&S{}) 258 259 func (s *S) SetUpSuite(c *check.C) { 260 mode := []string{TD234: "Top-Down 2-3-4", BU23: "Bottom-Up 2-3"} 261 fmt.Printf("Testing %s Left-Leaning Red Black Tree package.\n", mode[Mode]) 262 } 263 264 func (s *S) TestMakeAndDescribeTree(c *check.C) { 265 c.Check(describeTree((*Node)(nil), true, false), check.Equals, "();") 266 for _, desc := range []string{ 267 "();", 268 "((a,c)b,(e,g)f)d;", 269 } { 270 t := makeTree(desc) 271 c.Check(describeTree(t, true, false), check.Equals, desc) 272 } 273 } 274 275 // ((a,c)b,(e,g)f)d -rotL-> (((a,c)b,e)d,g)f 276 func (s *S) TestRotateLeft(c *check.C) { 277 orig := "((a,c)b,(e,g)f)d;" 278 rot := "(((a,c)b,e)d,g)f;" 279 280 tree := makeTree(orig) 281 282 tree = tree.rotateLeft() 283 c.Check(describeTree(tree, true, false), check.Equals, rot) 284 285 rotTree := makeTree(rot) 286 c.Check(tree, check.DeepEquals, rotTree) 287 } 288 289 // ((a,c)b,(e,g)f)d -rotR-> (a,(c,(e,g)f)d)b 290 func (s *S) TestRotateRight(c *check.C) { 291 orig := "((a,c)b,(e,g)f)d;" 292 rot := "(a,(c,(e,g)f)d)b;" 293 294 tree := makeTree(orig) 295 296 tree = tree.rotateRight() 297 c.Check(describeTree(tree, true, false), check.Equals, rot) 298 299 rotTree := makeTree(rot) 300 c.Check(tree, check.DeepEquals, rotTree) 301 } 302 303 func (s *S) TestNilOperations(c *check.C) { 304 t := &Tree{} 305 c.Check(t.Min(), check.Equals, nil) 306 c.Check(t.Max(), check.Equals, nil) 307 if Mode == TD234 { 308 return 309 } 310 t.DeleteMin() 311 c.Check(*t, check.Equals, Tree{}) 312 t.DeleteMax() 313 c.Check(*t, check.Equals, Tree{}) 314 } 315 316 func (s *S) TestInsertion(c *check.C) { 317 min, max := compRune(0), compRune(1000) 318 t := &Tree{} 319 for i := min; i <= max; i++ { 320 t.Insert(i) 321 c.Check(t.Len(), check.Equals, int(i+1)) 322 failed := false 323 failed = failed || !c.Check(t.isBST(), check.Equals, true) 324 failed = failed || !c.Check(t.is23_234(), check.Equals, true) 325 failed = failed || !c.Check(t.isBalanced(), check.Equals, true) 326 if failed { 327 if *printTree { 328 c.Logf("Failing tree: %s\n\n", describeTree(t.Root, false, true)) 329 } 330 if *genDot && t.Len() <= *dotLimit { 331 err := dotFile(t, fmt.Sprintf("TestInsertion_after_ins_%d", i), "") 332 if err != nil { 333 c.Errorf("Dot file write failed: %v", err) 334 } 335 } 336 c.Fatal("Cannot continue test: invariant contradiction") 337 } 338 } 339 c.Check(t.Min(), check.Equals, compRune(min)) 340 c.Check(t.Max(), check.Equals, compRune(max)) 341 } 342 343 func (s *S) TestDeletion(c *check.C) { 344 min, max := compRune(0), compRune(10000) 345 e := int(max-min) + 1 346 t := &Tree{} 347 for i := min; i <= max; i++ { 348 t.Insert(i) 349 } 350 for i := min; i <= max; i++ { 351 var dotString string 352 if t.Get(i) != nil { 353 e-- 354 } 355 if *genDot && t.Len() <= *dotLimit { 356 dotString = dot(t, fmt.Sprintf("TestDeletion_before_%d", i)) 357 } 358 t.Delete(i) 359 c.Check(t.Len(), check.Equals, e) 360 if i < max { 361 failed := false 362 failed = failed || !c.Check(t.isBST(), check.Equals, true) 363 failed = failed || !c.Check(t.is23_234(), check.Equals, true) 364 failed = failed || !c.Check(t.isBalanced(), check.Equals, true) 365 if failed { 366 if *printTree { 367 c.Logf("Failing tree: %s\n\n", describeTree(t.Root, false, true)) 368 } 369 if *genDot && t.Len() < *dotLimit { 370 var err error 371 err = dotFile(nil, fmt.Sprintf("TestDeletion_before_del_%d", i), dotString) 372 if err != nil { 373 c.Errorf("Dot file write failed: %v", err) 374 } 375 err = dotFile(t, fmt.Sprintf("TestDeletion_after_del_%d", i), "") 376 if err != nil { 377 c.Errorf("Dot file write failed: %v", err) 378 } 379 } 380 c.Fatal("Cannot continue test: invariant contradiction") 381 } 382 } 383 } 384 c.Check(*t, check.Equals, Tree{}) 385 } 386 387 func (s *S) TestGet(c *check.C) { 388 min, max := compRune(0), compRune(100000) 389 t := &Tree{} 390 for i := min; i <= max; i++ { 391 if i&1 == 0 { 392 t.Insert(i) 393 } 394 } 395 for i := min; i <= max; i++ { 396 if i&1 == 0 { 397 c.Check(t.Get(i), check.Equals, compRune(i)) // Check inserted elements are present. 398 } else { 399 c.Check(t.Get(i), check.Equals, Comparable(nil)) // Check inserted elements are absent. 400 } 401 } 402 } 403 404 func (s *S) TestFloor(c *check.C) { 405 min, max := compRune(0), compRune(100000) 406 t := &Tree{} 407 for i := min; i <= max; i++ { 408 if i&1 == 0 { // Insert even numbers only. 409 t.Insert(i) 410 } 411 } 412 for i := min; i <= max; i++ { 413 if i&1 == 0 { 414 c.Check(t.Floor(i), check.Equals, compRune(i)) // Check even Floors are themselves. 415 } else { 416 c.Check(t.Floor(i), check.Equals, compRune(i-1)) // Check odd Floors are the previous number. 417 } 418 } 419 c.Check(t.Floor(min-1), check.Equals, Comparable(nil)) 420 } 421 422 func (s *S) TestCeil(c *check.C) { 423 min, max := compRune(0), compRune(100000) 424 t := &Tree{} 425 for i := min; i <= max; i++ { 426 if i&1 == 1 { // Insert odd numbers only. 427 t.Insert(i) 428 } 429 } 430 for i := min; i < max; i++ { 431 if i&1 == 1 { 432 c.Check(t.Ceil(i), check.Equals, compRune(i)) // Check odd Ceils are themselves. 433 } else { 434 c.Check(t.Ceil(i), check.Equals, compRune(i+1)) // Check even Ceils are the next number. 435 } 436 } 437 c.Check(t.Ceil(max+1), check.Equals, Comparable(nil)) 438 } 439 440 func (s *S) TestUpper(c *check.C) { 441 min, max := compInt(0), compInt(100000) 442 t := &Tree{} 443 for i := min; i <= max; i++ { 444 if i&1 == 1 { // Insert odd numbers only. 445 t.Insert(i) 446 } 447 } 448 for i := min; i < max-1; i++ { 449 if i&1 == 1 { 450 c.Check(t.Ceil(compIntUpper(i)), check.Equals, compInt(i+2)) // Check odd Uppers are the next odd. 451 } else { 452 c.Check(t.Ceil(compIntUpper(i)), check.Equals, compInt(i+1)) // Check even Uppers are the next number. 453 } 454 } 455 c.Check(t.Ceil(compIntUpper(max+1)), check.Equals, Comparable(nil)) 456 } 457 458 func (s *S) TestRandomlyInsertedGet(c *check.C) { 459 count, max := 100000, 1000 460 t := &Tree{} 461 verify := map[rune]struct{}{} 462 for i := 0; i < count; i++ { 463 v := compRune(rand.Intn(max)) 464 t.Insert(v) 465 verify[rune(v)] = struct{}{} 466 } 467 // Random fetch order - check only those inserted. 468 for v := range verify { 469 c.Check(t.Get(compRune(v)), check.Equals, compRune(v)) // Check inserted elements are present. 470 } 471 // Check all possible insertions. 472 for i := compRune(0); i <= compRune(max); i++ { 473 if _, ok := verify[rune(i)]; ok { 474 c.Check(t.Get(i), check.Equals, compRune(i)) // Check inserted elements are present. 475 } else { 476 c.Check(t.Get(i), check.Equals, Comparable(nil)) // Check inserted elements are absent. 477 } 478 } 479 } 480 481 func (s *S) TestRandomInsertion(c *check.C) { 482 count, max := 100000, 1000 483 t := &Tree{} 484 for i := 0; i < count; i++ { 485 r := rand.Intn(max) 486 t.Insert(compRune(r)) 487 failed := false 488 failed = failed || !c.Check(t.isBST(), check.Equals, true) 489 failed = failed || !c.Check(t.is23_234(), check.Equals, true) 490 failed = failed || !c.Check(t.isBalanced(), check.Equals, true) 491 if failed { 492 if *printTree { 493 c.Logf("Failing tree: %s\n\n", describeTree(t.Root, false, true)) 494 } 495 if *genDot && t.Len() <= *dotLimit { 496 err := dotFile(t, fmt.Sprintf("TestRandomInsertion_after_ins_%d", r), "") 497 if err != nil { 498 c.Errorf("Dot file write failed: %v", err) 499 } 500 } 501 c.Fatal("Cannot continue test: invariant contradiction") 502 } 503 } 504 } 505 506 func (s *S) TestRandomDeletion(c *check.C) { 507 var ( 508 count, max = 100000, 1000 509 r = make([]compRune, count) 510 t = &Tree{} 511 ) 512 for i := range r { 513 r[i] = compRune(rand.Intn(max)) 514 t.Insert(r[i]) 515 } 516 for _, v := range r { 517 t.Delete(v) 518 if t != nil { 519 failed := false 520 failed = failed || !c.Check(t.isBST(), check.Equals, true) 521 failed = failed || !c.Check(t.is23_234(), check.Equals, true) 522 failed = failed || !c.Check(t.isBalanced(), check.Equals, true) 523 if failed { 524 if *printTree { 525 c.Logf("Failing tree: %s\n\n", describeTree(t.Root, false, true)) 526 } 527 if *genDot && t.Len() <= *dotLimit { 528 err := dotFile(t, fmt.Sprintf("TestRandomDeletion_after_del_%d", v), "") 529 if err != nil { 530 c.Errorf("Dot file write failed: %v", err) 531 } 532 } 533 c.Fatal("Cannot continue test: invariant contradiction") 534 } 535 } 536 } 537 c.Check(*t, check.Equals, Tree{}) 538 } 539 540 type compStructUpper struct { 541 key int 542 val byte 543 } 544 545 func (cs compStructUpper) Compare(s Comparable) (c int) { 546 c = cs.key - s.(compStructUpper).key 547 if c == 0 { 548 c = int(cs.val) - int(s.(compStructUpper).val) 549 } 550 return c 551 } 552 func (cs compStructUpper) String() string { return fmt.Sprintf("[%d:%c]", cs.key, cs.val) } 553 554 func (s *S) TestNonUniqueDeletion(c *check.C) { 555 var ( 556 r = []compStructUpper{{1, 'a'}, {1, 'b'}, {1, 'c'}, {0, 'd'}} 557 t = &Tree{} 558 ) 559 for i, v := range r { 560 t.Insert(v) 561 c.Check(t.Len(), check.Equals, i+1) 562 } 563 for _, v := range r { 564 var dotString string 565 if *genDot && t.Len() <= *dotLimit { 566 dotString = dot(t, "TestNonUniqueDeletion_before_del") 567 } 568 t.Delete(v) 569 if t != nil { 570 failed := false 571 failed = failed || !c.Check(t.is23_234(), check.Equals, true) 572 failed = failed || !c.Check(t.isBalanced(), check.Equals, true) 573 if failed { 574 if *printTree { 575 c.Logf("Failing tree: %s\n\n", describeTree(t.Root, false, true)) 576 } 577 if *genDot && t.Len() <= *dotLimit { 578 var err error 579 err = dotFile(nil, "TestNonUniqueDeletion_before_del", dotString) 580 if err != nil { 581 c.Errorf("Dot file write failed: %v", err) 582 } 583 err = dotFile(t, "TestNonUniqueDeletion_after_del", "") 584 if err != nil { 585 c.Errorf("Dot file write failed: %v", err) 586 } 587 } 588 c.Fatal("Cannot continue test: invariant contradiction") 589 } 590 } 591 } 592 c.Check(*t, check.Equals, Tree{}) 593 } 594 595 func (s *S) TestDeleteMinMax(c *check.C) { 596 var ( 597 min, max = compRune(0), compRune(10) 598 t = &Tree{} 599 dI int 600 ) 601 for i := min; i <= max; i++ { 602 t.Insert(i) 603 dI = t.Len() 604 } 605 c.Check(dI, check.Equals, int(max-min+1)) 606 for i, m := 0, int(max); i < m/2; i++ { 607 var failed bool 608 t.DeleteMin() 609 dI-- 610 c.Check(t.Len(), check.Equals, dI) 611 min++ 612 failed = !c.Check(t.Min(), check.Equals, min) 613 failed = failed || !c.Check(t.isBST(), check.Equals, true) 614 failed = failed || !c.Check(t.is23_234(), check.Equals, true) 615 failed = failed || !c.Check(t.isBalanced(), check.Equals, true) 616 if failed { 617 if *printTree { 618 c.Logf("Failing tree: %s\n\n", describeTree(t.Root, false, true)) 619 } 620 if *genDot && t.Len() <= *dotLimit { 621 err := dotFile(t, fmt.Sprintf("TestDeleteMinMax_after_delmin_%d", i), "") 622 if err != nil { 623 c.Errorf("Dot file write failed: %v", err) 624 } 625 } 626 c.Fatal("Cannot continue test: invariant contradiction") 627 } 628 t.DeleteMax() 629 dI-- 630 c.Check(t.Len(), check.Equals, dI) 631 max-- 632 failed = !c.Check(t.Max(), check.Equals, max) 633 failed = failed || !c.Check(t.isBST(), check.Equals, true) 634 failed = failed || !c.Check(t.is23_234(), check.Equals, true) 635 failed = failed || !c.Check(t.isBalanced(), check.Equals, true) 636 if failed { 637 if *printTree { 638 c.Logf("Failing tree: %s\n\n", describeTree(t.Root, false, true)) 639 } 640 if *genDot && t.Len() <= *dotLimit { 641 err := dotFile(t, fmt.Sprintf("TestDeleteMinMax_after_delmax_%d", i), "") 642 if err != nil { 643 c.Errorf("Dot file write failed: %v", err) 644 } 645 } 646 c.Fatal("Cannot continue test: invariant contradiction") 647 } 648 } 649 } 650 651 func (s *S) TestRandomInsertionDeletion(c *check.C) { 652 var ( 653 count, max = 100000, 1000 654 t = &Tree{} 655 verify = map[int]struct{}{} 656 ) 657 for i := 0; i < count; i++ { 658 var ( 659 failed bool 660 rI, rD int 661 dotString string 662 ) 663 if rand.Float64() < 0.5 { 664 rI = rand.Intn(max) 665 t.Insert(compRune(rI)) 666 verify[rI] = struct{}{} 667 c.Check(t.Len(), check.Equals, len(verify)) 668 } 669 failed = !c.Check(t.isBST(), check.Equals, true) 670 failed = failed || !c.Check(t.is23_234(), check.Equals, true) 671 failed = failed || !c.Check(t.isBalanced(), check.Equals, true) 672 if *genDot && t.Len() <= *dotLimit { 673 dotString = dot(t, fmt.Sprintf("TestRandomInsertionDeletion_after_ins_%d_%d", i, rI)) 674 } 675 if failed { 676 if *printTree { 677 c.Logf("Failing tree: %s\n\n", describeTree(t.Root, false, true)) 678 } 679 if *genDot && t.Len() <= *dotLimit { 680 err := dotFile(nil, fmt.Sprintf("TestRandomInsertionDeletion_after_ins_%d_%d", i, rI), dotString) 681 if err != nil { 682 c.Errorf("Dot file write failed: %v", err) 683 } 684 } 685 c.Fatal("Cannot continue test: invariant contradiction") 686 } 687 if rand.Float64() < 0.5 { 688 rD = rand.Intn(max) 689 t.Delete(compRune(rD)) 690 delete(verify, rD) 691 c.Check(t.Len(), check.Equals, len(verify)) 692 } else { 693 continue 694 } 695 failed = !c.Check(t.isBST(), check.Equals, true) 696 failed = failed || !c.Check(t.is23_234(), check.Equals, true) 697 failed = failed || !c.Check(t.isBalanced(), check.Equals, true) 698 if failed { 699 if *printTree { 700 c.Logf("Failing tree: %s\n\n", describeTree(t.Root, false, true)) 701 } 702 if *genDot && t.Len() <= *dotLimit { 703 var err error 704 err = dotFile(nil, fmt.Sprintf("TestRandomInsertionDeletion_after_ins_%d_%d", i, rI), dotString) 705 if err != nil { 706 c.Errorf("Dot file write failed: %v", err) 707 } 708 err = dotFile(t, fmt.Sprintf("TestRandomInsertionDeletion_after_del_%d_%d", i, rD), "") 709 if err != nil { 710 c.Errorf("Dot file write failed: %v", err) 711 } 712 } 713 c.Fatal("Cannot continue test: invariant contradiction") 714 } 715 } 716 } 717 718 func (s *S) TestDeleteRight(c *check.C) { 719 type target struct { 720 min, max, target compRune 721 } 722 for _, r := range []target{ 723 {0, 14, -1}, 724 {0, 14, 14}, 725 {0, 14, 15}, 726 {0, 15, -1}, 727 {0, 15, 15}, 728 {0, 15, 16}, 729 {0, 16, -1}, 730 {0, 16, 15}, 731 {0, 16, 16}, 732 {0, 16, 17}, 733 {0, 17, -1}, 734 {0, 17, 16}, 735 {0, 17, 17}, 736 {0, 17, 18}, 737 } { 738 var format, dotString string 739 t := &Tree{} 740 for i := r.min; i <= r.max; i++ { 741 t.Insert(i) 742 } 743 before := describeTree(t.Root, false, true) 744 format = "Before deletion: %#v %s" 745 ok := checkTree(t, c, format, r, before) 746 if !ok { 747 c.Fatal("Cannot continue test: invariant contradiction") 748 } 749 if *genDot && t.Len() <= *dotLimit { 750 dotString = dot(t, strings.Replace( 751 fmt.Sprintf("TestDeleteRight_%s_before_del_%d_%d_%d", modeName[Mode], r.min, r.max, r.target), 752 "-", "_", -1)) 753 } 754 t.Delete(r.target) 755 if r.min <= r.target && r.target <= r.max { 756 c.Check(t.Len(), check.Equals, int(r.max-r.min)) // Key in tree. 757 } else { 758 c.Check(t.Len(), check.Equals, int(r.max-r.min)+1) // Key not in tree. 759 } 760 format = "%#v\nBefore deletion: %s\nAfter deletion: %s" 761 ok = checkTree(t, c, format, r, before, describeTree(t.Root, false, true)) 762 if !ok && *genDot && t.Len() < *dotLimit { 763 var err error 764 err = dotFile(nil, strings.Replace( 765 fmt.Sprintf("TestDeleteRight_%s_before_del_%d_%d_%d", modeName[Mode], r.min, r.max, r.target), 766 "-", "_", -1), dotString) 767 if err != nil { 768 c.Errorf("Dot file write failed: %v", err) 769 } 770 err = dotFile(t, strings.Replace( 771 fmt.Sprintf("TestDeleteRight_%s_after_del_%d_%d_%d", modeName[Mode], r.min, r.max, r.target), 772 "-", "_", -1), "") 773 if err != nil { 774 c.Errorf("Dot file write failed: %v", err) 775 } 776 } 777 } 778 } 779 780 func checkTree(t *Tree, c *check.C, f string, i ...interface{}) (ok bool) { 781 comm := check.Commentf(f, i...) 782 ok = true 783 ok = ok && c.Check(t.isBST(), check.Equals, true, comm) 784 ok = ok && c.Check(t.is23_234(), check.Equals, true, comm) 785 ok = ok && c.Check(t.isBalanced(), check.Equals, true, comm) 786 return 787 } 788 789 var ( 790 modeName = []string{TD234: "TD234", BU23: "BU23"} 791 arrows = map[Color]string{Red: "none", Black: "normal"} 792 ) 793 794 func dot(t *Tree, label string) string { 795 if t == nil { 796 return "" 797 } 798 var ( 799 s []string 800 follow func(*Node) 801 ) 802 follow = func(n *Node) { 803 id := uintptr(unsafe.Pointer(n)) 804 c := fmt.Sprintf("%d[label = \"<Left> |<Elem> %v|<Right>\"];", id, n.Elem) 805 if n.Left != nil { 806 c += fmt.Sprintf("\n\t\tedge [color=%v,arrowhead=%s]; \"%d\":Left -> \"%d\":Elem;", 807 n.Left.color(), arrows[n.Left.color()], id, uintptr(unsafe.Pointer(n.Left))) 808 follow(n.Left) 809 } 810 if n.Right != nil { 811 c += fmt.Sprintf("\n\t\tedge [color=%v,arrowhead=%s]; \"%d\":Right -> \"%d\":Elem;", 812 n.Right.color(), arrows[n.Right.color()], id, uintptr(unsafe.Pointer(n.Right))) 813 follow(n.Right) 814 } 815 s = append(s, c) 816 } 817 if t.Root != nil { 818 follow(t.Root) 819 } 820 return fmt.Sprintf("digraph %s {\n\tnode [shape=record,height=0.1];\n\t%s\n}\n", 821 label, 822 strings.Join(s, "\n\t"), 823 ) 824 } 825 826 func dotFile(t *Tree, label, dotString string) (err error) { 827 if t == nil && dotString == "" { 828 return 829 } 830 f, err := os.Create(label + ".dot") 831 if err != nil { 832 return 833 } 834 defer f.Close() 835 if dotString == "" { 836 fmt.Fprintf(f, dot(t, label)) 837 } else { 838 fmt.Fprintf(f, dotString) 839 } 840 return 841 } 842 843 // Test values for range methods. 844 var values = compInts{-10, -32, 100, 46, 239, 2349, 101, 0, 1} 845 846 func (s *S) TestDo(c *check.C) { 847 values := append(compInts(nil), values...) 848 t := &Tree{} 849 for _, v := range values { 850 t.Insert(v) 851 } 852 var result compInts 853 f := func(c Comparable) (done bool) { 854 result = append(result, c.(compInt)) 855 return 856 } 857 killed := t.Do(f) 858 sort.Sort(values) 859 c.Check(result, check.DeepEquals, values) 860 c.Check(killed, check.Equals, false) 861 } 862 863 func (s *S) TestDoShortCircuit(c *check.C) { 864 values := append(compInts(nil), values...) 865 elem := 3 866 t := &Tree{} 867 for _, v := range values { 868 t.Insert(v) 869 } 870 sort.Sort(values) 871 target := values[elem] 872 var result compInts 873 f := func(c Comparable) (done bool) { 874 result = append(result, c.(compInt)) 875 if target.Compare(c) == 0 { 876 done = true 877 } 878 return 879 } 880 killed := t.Do(f) 881 c.Check(result, check.DeepEquals, values[:elem+1]) 882 c.Check(killed, check.Equals, true) 883 } 884 885 func (s *S) TestDoReverse(c *check.C) { 886 values := append(compInts(nil), values...) 887 t := &Tree{} 888 for _, v := range values { 889 t.Insert(v) 890 } 891 var result compInts 892 f := func(c Comparable) (done bool) { 893 result = append(result, c.(compInt)) 894 return 895 } 896 killed := t.DoReverse(f) 897 sort.Sort(Reverse{values}) 898 c.Check(result, check.DeepEquals, values) 899 c.Check(killed, check.Equals, false) 900 } 901 902 func (s *S) TestDoRange(c *check.C) { 903 values := append(compInts(nil), values...) 904 lo, hi := compInt(0), compInt(100) 905 var limValues compInts 906 t := &Tree{} 907 for _, v := range values { 908 t.Insert(v) 909 if v >= lo && v < hi { 910 limValues = append(limValues, v) 911 } 912 } 913 var result compInts 914 f := func(c Comparable) (done bool) { 915 result = append(result, c.(compInt)) 916 return 917 } 918 killed := t.DoRange(f, lo, hi) 919 sort.Sort(limValues) 920 c.Check(result, check.DeepEquals, limValues) 921 c.Check(killed, check.Equals, false) 922 } 923 924 func (s *S) TestDoRangeReverse(c *check.C) { 925 values := append(compInts(nil), values...) 926 lo, hi := compInt(0), compInt(100) 927 var limValues compInts 928 t := &Tree{} 929 for _, v := range values { 930 t.Insert(v) 931 if v >= lo && v < hi { 932 limValues = append(limValues, v) 933 } 934 } 935 var result compInts 936 f := func(c Comparable) (done bool) { 937 result = append(result, c.(compInt)) 938 return 939 } 940 killed := t.DoRangeReverse(f, hi, lo) 941 sort.Sort(Reverse{limValues}) 942 c.Check(result, check.DeepEquals, limValues) 943 c.Check(killed, check.Equals, false) 944 } 945 946 func (s *S) TestDoMatch(c *check.C) { 947 values := append(compInts(nil), values...) 948 elem := 3 949 t := &Tree{} 950 for _, v := range values { 951 t.Insert(v) 952 } 953 sort.Sort(values) 954 target := values[elem] 955 f := func(r Comparable) (done bool) { 956 c.Check(r, check.Equals, target) 957 return 958 } 959 killed := t.DoMatching(f, target) 960 c.Check(killed, check.Equals, false) 961 } 962 963 // Benchmarks 964 965 func BenchmarkInsert(b *testing.B) { 966 t := &Tree{} 967 for i := 0; i < b.N; i++ { 968 t.Insert(compInt(b.N - i)) 969 } 970 } 971 972 func BenchmarkInsertNoRep(b *testing.B) { 973 t := &Tree{} 974 for i := 0; i < b.N; i++ { 975 t.Insert(compIntUpper(b.N - i)) 976 } 977 } 978 979 func BenchmarkGet(b *testing.B) { 980 b.StopTimer() 981 t := &Tree{} 982 for i := 0; i < b.N; i++ { 983 t.Insert(compInt(b.N - i)) 984 } 985 b.StartTimer() 986 for i := 0; i < b.N; i++ { 987 t.Get(compInt(i)) 988 } 989 } 990 991 func BenchmarkMin(b *testing.B) { 992 b.StopTimer() 993 t := &Tree{} 994 for i := 0; i < 1e5; i++ { 995 t.Insert(compInt(i)) 996 } 997 b.StartTimer() 998 var m Comparable 999 for i := 0; i < b.N; i++ { 1000 m = t.Min() 1001 } 1002 _ = m 1003 } 1004 1005 func BenchmarkMax(b *testing.B) { 1006 b.StopTimer() 1007 t := &Tree{} 1008 for i := 0; i < 1e5; i++ { 1009 t.Insert(compInt(i)) 1010 } 1011 b.StartTimer() 1012 var m Comparable 1013 for i := 0; i < b.N; i++ { 1014 m = t.Max() 1015 } 1016 _ = m 1017 } 1018 1019 func BenchmarkDelete(b *testing.B) { 1020 b.StopTimer() 1021 t := &Tree{} 1022 for i := 0; i < b.N; i++ { 1023 t.Insert(compInt(b.N - i)) 1024 } 1025 b.StartTimer() 1026 for i := 0; i < b.N; i++ { 1027 t.Delete(compInt(i)) 1028 } 1029 } 1030 1031 func BenchmarkDeleteMin(b *testing.B) { 1032 b.StopTimer() 1033 t := &Tree{} 1034 for i := 0; i < b.N; i++ { 1035 t.Insert(compInt(b.N - i)) 1036 } 1037 b.StartTimer() 1038 for i := 0; i < b.N; i++ { 1039 t.DeleteMin() 1040 } 1041 } 1042 1043 // Benchmarks for comparison to the built-in type. 1044 1045 func BenchmarkInsertMap(b *testing.B) { 1046 var m = map[int]struct{}{} 1047 for i := 0; i < b.N; i++ { 1048 m[i] = struct{}{} 1049 } 1050 } 1051 1052 func BenchmarkGetMap(b *testing.B) { 1053 b.StopTimer() 1054 var m = map[int]struct{}{} 1055 for i := 0; i < b.N; i++ { 1056 m[i] = struct{}{} 1057 } 1058 b.StartTimer() 1059 var r struct{} 1060 for i := 0; i < b.N; i++ { 1061 r = m[i] 1062 } 1063 _ = r 1064 } 1065 1066 func BenchmarkDeleteMap(b *testing.B) { 1067 b.StopTimer() 1068 var m = map[int]struct{}{} 1069 for i := 0; i < b.N; i++ { 1070 m[i] = struct{}{} 1071 } 1072 b.StartTimer() 1073 for i := 0; i < b.N; i++ { 1074 delete(m, i) 1075 } 1076 }