1 module PixelPerfectEngine.system.binarySearchTree; 2 3 /* 4 * Copyright (C) 2015-2018, by Laszlo Szeremi under the Boost license. 5 * 6 * Pixel Perfect Engine, system.transformFunctions module 7 */ 8 9 import core.stdc.stdlib; 10 import core.stdc..string; 11 12 /** 13 * Implements a mostly @nogc-able container format, with relatively fast access times. 14 * Mostly based upon the AVT tree algorithm with small modifications, with the intent to replace D's default associative arrays for GC-free operations, 15 * and better speed (theoretical worst-case access times: aArray's = n, this' = log2(n)). 16 * Tree traversal through D's Range capabilities. 17 * TODO: 18 * <ul> 19 * <li>Implement tree traversal.</li> 20 * <li>Improve tree optimization speeds.</li> 21 * <li>Fix potential memory leakage issues.</li> 22 * </ul> 23 */ 24 public struct BinarySearchTree(K, E){ 25 /** 26 * Implements a single tree node. 27 */ 28 public struct Node{ 29 K key; ///Indentifier key, also used for automatic sorting 30 E elem; ///Stores the element referred by this node 31 Node* left; ///lesser elements 32 Node* right; ///greater elements 33 34 @nogc this(K key, E elem, Node* left = null, Node* right = null){ 35 this.key = key; 36 this.elem = elem; 37 this.left = left; 38 this.right = right; 39 } 40 41 @nogc int opApply(int delegate(Node) @nogc dg){ 42 if(left) 43 if(left.opApply(dg)) 44 return 1; 45 if(dg(this)) 46 return 1; 47 if(right) 48 if(right.opApply(dg)) 49 return 1; 50 return 0; 51 } 52 @nogc int opCmp(ref Node rhs){ 53 return key - rhs.key; 54 } 55 /** 56 * Returns the total height. 57 */ 58 @nogc @property size_t height(){ 59 if(left is null && right is null){ 60 return 1; 61 }else{ 62 size_t l = 1, r = 1; 63 if(left !is null){ 64 l += left.height; 65 } 66 if(right !is null){ 67 r += right.height; 68 } 69 if(l >= r){ 70 return l; 71 }else{ 72 return r; 73 } 74 } 75 } 76 /** 77 * Returns the balance of the node. Minus if LHS is heavier, plus if RHS is heavier. 78 */ 79 @nogc @property sizediff_t bal(){ 80 if(left is null && right is null){ 81 return 0; 82 }else{ 83 size_t l, r; 84 if(left !is null){ 85 l = left.height; 86 } 87 if(right !is null){ 88 r = right.height; 89 } 90 return r - l; 91 } 92 } 93 /** 94 * Deallocates the memory allocated for the tree. 95 */ 96 @nogc void dealloc(){ 97 if(left){ 98 left.dealloc; 99 free(left); 100 } 101 if(right){ 102 right.dealloc; 103 free(right); 104 } 105 } 106 /** 107 * String representation for debugging. 108 */ 109 public string toString(){ 110 import std.conv; 111 string result = "[" ~ to!string(key) ~ ":" ~ to!string(elem) ~ ";" ~ to!string(bal) ~ ";"; 112 if(left is null){ 113 result ~= "lhs: null "; 114 }else{ 115 result ~= " lhs: " ~ left.toString; 116 } 117 if(right is null){ 118 result ~= "rhs: null "; 119 }else{ 120 result ~= " rhs: " ~ right.toString; 121 } 122 return result ~ "]"; 123 } 124 } 125 private Node* root; ///Points to the root element 126 private size_t nOfElements; ///Current number of elements 127 /+private size_t curr, currHeight; 128 private Node** traceF, traceR; ///Used for Range 129 private Node* pos;+/ 130 131 /+/** 132 * Returns true if the range have reached one of the endpoints. 133 */ 134 public @nogc bool empty(){ 135 return nOfElements == curr; 136 } 137 /** 138 * Returns the front element. 139 */ 140 public @nogc Node front(){ 141 return *pos; 142 } 143 /** 144 * Jumps to the next front element and returns it. 145 */ 146 public @nogc Node popFront(){ 147 //if trace isn't allocated, then allocate it 148 if(traceF is null){ 149 size_t height = root.height; 150 traceF = cast(Node**)malloc(size_t.sizeof * height); 151 while(--height){ 152 traceF[height] = null; 153 } 154 traceF[0] = root; 155 //build up initial trace then return the smallest value 156 bool found; 157 while(!found){ 158 if(traceF[currHeight].left !is null){ 159 currHeight++; 160 }else{ 161 pos = traceF[currHeight]; 162 found = true; 163 } 164 } 165 return *pos; 166 } 167 //find the next smallest node 168 bool found; 169 K key = pos.key; 170 while(!found){ 171 if(traceF[currHeight].key > pos.key){ 172 found = true 173 } 174 } 175 curr++; 176 return *pos; 177 }+/ 178 /** 179 * Used for foreach iteration. 180 */ 181 public @nogc int opApply(int delegate(Node) @nogc dg){ 182 return root.opApply(dg); 183 } 184 /** 185 * Gets an element without allocation. Returns E.init if key not found. 186 */ 187 public @nogc E opIndex(K key){ 188 bool found; 189 Node* crnt = root; 190 E result; 191 do{ 192 if(crnt is null){ 193 found = true; 194 }else if(crnt.key == key){ 195 found = true; 196 result = crnt.elem; 197 }else if(crnt.key > key){ 198 crnt = crnt.left; 199 }else{ 200 crnt = crnt.right; 201 } 202 }while(!found); 203 return result; 204 } 205 /** 206 * Gets the pointer of an element. 207 */ 208 public @nogc E* getPtr(K key){ 209 bool found; 210 Node* crnt = root; 211 E* result; 212 do{ 213 if(crnt is null){ 214 found = true; 215 }else if(crnt.key == key){ 216 found = true; 217 result = &crnt.elem; 218 }else if(crnt.key > key){ 219 crnt = crnt.left; 220 }else{ 221 crnt = crnt.right; 222 } 223 }while(!found); 224 return result; 225 } 226 /** 227 * Inserts a new element with some automatic optimization. 228 * TODO: Make the optimization better. 229 */ 230 public @nogc E opIndexAssign(E value, K i){ 231 if(root is null){ 232 root = cast(Node*)malloc(Node.sizeof); 233 *root = Node(i,value); 234 nOfElements++; 235 return value; 236 } 237 if(insertAt(&root, i, value)){ 238 rebalanceTree(&root); 239 nOfElements++; 240 } 241 return value; 242 } 243 /** 244 * Rebalances a tree. 245 */ 246 public @nogc void rebalanceTree(){ 247 rebalanceTree(&root); 248 } 249 protected @nogc void rebalanceTree(Node** node){ 250 if((*node).height > 1){ 251 if((*node).bal > 1 || (*node).bal < -1){ 252 optimize(node); 253 } 254 if((*node).left !is null){ 255 rebalanceTree(&(*node).left); 256 } 257 if((*node).right !is null){ 258 rebalanceTree(&(*node).right); 259 } 260 } 261 } 262 /** 263 * Returns the number of elements in the tree. 264 */ 265 public @nogc @property size_t length(){ 266 return nOfElements; 267 } 268 /** 269 * Inserts an item at the given point. Returns true if the height of the tree have been raised. 270 */ 271 protected @nogc bool insertAt(Node** node, K key, E val){ 272 if(key == (*node).key){ 273 (*node).elem = val; 274 return false; 275 }else if(key < (*node).key){ 276 if((*node).left is null){ 277 (*node).left = cast(Node*)malloc(Node.sizeof); 278 *(*node).left = Node(key,val); 279 if((*node).right is null){ 280 return true; 281 }else{ 282 return false; 283 } 284 }else{ 285 return insertAt(&((*node).left), key, val); 286 } 287 }else{ 288 if((*node).right is null){ 289 (*node).right = cast(Node*)malloc(Node.sizeof); 290 *(*node).right = Node(key,val); 291 if((*node).left is null){ 292 return true; 293 }else{ 294 return false; 295 } 296 }else{ 297 return insertAt(&((*node).right), key, val); 298 } 299 } 300 } 301 /** 302 * Removes an element by key. 303 */ 304 public @nogc void remove(K key){ 305 bool handside; 306 Node* crnt = root; 307 Node* prev; 308 while(crnt !is null){ 309 if(crnt.key == key){ 310 if(crnt.left is null && crnt.right is null){ 311 free(crnt); 312 if(prev !is null){ 313 if(handside) 314 prev.right = null; 315 else 316 prev.left = null; 317 }else{ 318 root = null; 319 } 320 crnt = null; 321 nOfElements--; 322 }else if(crnt.left is null){ 323 if(prev is null){ 324 root = crnt.right; 325 }else{ 326 if(handside) 327 prev.right = crnt.right; 328 else 329 prev.left = crnt.right; 330 } 331 free(crnt); 332 crnt = null; 333 nOfElements--; 334 }else if(crnt.right is null){ 335 if(prev is null){ 336 root = crnt.left; 337 }else{ 338 if(handside) 339 prev.right = crnt.left; 340 else 341 prev.left = crnt.left; 342 } 343 free(crnt); 344 crnt = null; 345 nOfElements--; 346 }else{ 347 Node* temp; 348 if(handside){ 349 temp = findMin(prev.right); 350 }else{ 351 temp = findMax(prev.right); 352 } 353 K tempKey = temp.key; 354 E tempVal = temp.elem; 355 Node* tempLHS = temp.left; 356 Node* tempRHS = temp.right; 357 remove(tempKey); 358 crnt.key = tempKey; 359 crnt.elem = tempVal; 360 crnt.left = tempLHS; 361 crnt.right = tempRHS; 362 return; 363 } 364 }else if(crnt.key > key){ 365 prev = crnt; 366 handside = false; 367 crnt = crnt.left; 368 }else{ 369 prev = crnt; 370 handside = true; 371 crnt = crnt.right; 372 } 373 } 374 } 375 /** 376 * Rotates the subtree to the left by one. 377 */ 378 protected @nogc void rotateLeft(Node** node){ 379 /*Node* temp = (*node).right; 380 (*node).right = temp.left; 381 temp.left = *node; 382 *node = temp; 383 (*node).bal = 0; 384 temp.bal = 0;*/ 385 Node* temp = *node; //save current node 386 *node = temp.right; //assign the first RHS to the root 387 temp.right = (*node).left; //assign the new root's LHS to the saved node's RHS 388 (*node).left = temp; //assign the saved node to the new root's LHS 389 //(*node).bal = 0; //reset new root's balance 390 //temp.bal = 0; //reset the new LHS's balance 391 } 392 /** 393 * Rotates the subtree to the right by one. 394 */ 395 protected @nogc void rotateRight(Node** node){ 396 /*Node* temp = (*node).left; 397 (*node).left = temp.right; 398 temp.right = *node; 399 *node = temp; 400 (*node).bal = 0; 401 temp.bal = 0;*/ 402 Node* temp = *node; //save current node 403 *node = temp.left; //assign the first LHS to the root 404 temp.left = (*node).right; //assign the new root's RHS to the saved node's LHS 405 (*node).right = temp; //assign the saved node to the new root's RHS 406 //(*node).bal = 0; //reset new root's balance 407 //temp.bal = 0; //reset the new RHS's balance 408 } 409 /** 410 * Rotates the subtree to the right then to the left. 411 */ 412 protected @nogc void rotateRightLeft(Node** node){ 413 Node* temp = (*node).right.left; //save root.RHS.LHS 414 (*node).right.left = temp.right; //assign temp.RHS to root.RHS.LHS 415 temp.right = (*node).right; //assign root.RHS to temp.RHS 416 (*node).right = temp; //assign temp to root.RHS 417 //temp.right.bal = 0; //reset balance of temp.RHS 418 rotateLeft(node); //rotate the root to the left 419 } 420 /** 421 * Rotates the subtree to the right then to the left. 422 */ 423 protected @nogc void rotateLeftRight(Node** node){ 424 Node* temp = (*node).left.right; //save root.LHS.RHS 425 (*node).left.right = temp.left; //assign temp.LHS to root.LHS.RHS 426 temp.left = (*node).left; //assign root.LHS to temp.LHS 427 (*node).left = temp; //assign temp to root.LHS 428 //temp.left.bal = 0; //reset balance of temp.LHS 429 rotateRight(node); //rotate the root to the right 430 } 431 /** 432 * Optimizes a BinarySearchTree by distributing nodes evenly. 433 */ 434 protected @nogc void optimize(Node** node){ 435 if((*node).bal >= 2){ 436 if((*node).right.bal >= 1){ 437 rotateLeft(node); 438 }else if((*node).right.bal <= -1){ 439 rotateRightLeft(node); 440 } 441 }else if((*node).bal <= -2){ 442 if((*node).left.bal >= 1){ 443 rotateLeftRight(node); 444 }else if((*node).left.bal <= -1){ 445 rotateRight(node); 446 } 447 } 448 449 } 450 451 public Node*[] collectNodes(Node* source){ 452 Node*[] result; 453 if(source !is null){ 454 result ~= source; 455 if(source.left !is null) 456 result ~= collectNodes(source.left); 457 if(source.right !is null) 458 result ~= collectNodes(source.right); 459 } 460 return result; 461 } 462 /** 463 * Finds the smallest value from the root. 464 */ 465 public @nogc Node* findMin(){ 466 bool found; 467 Node* result = root; 468 do{ 469 if(result.left is null) 470 found = true; 471 else 472 result = result.left; 473 }while(!found); 474 return result; 475 } 476 /** 477 * Finds the smallest value from the given root. 478 */ 479 public @nogc Node* findMin(Node* from){ 480 bool found; 481 Node* result = from; 482 do{ 483 if(result.left is null) 484 found = true; 485 else 486 result = result.left; 487 }while(!found); 488 return result; 489 } 490 /** 491 * Finds the largest value from the root. 492 */ 493 public @nogc Node* findMax(){ 494 bool found; 495 Node* result = root; 496 do{ 497 if(result.right is null) 498 found = true; 499 else 500 result = result.right; 501 }while(!found); 502 return result; 503 } 504 /** 505 * Finds the largest value from the given root. 506 */ 507 public @nogc Node* findMax(Node* from){ 508 bool found; 509 Node* result = from; 510 do{ 511 if(result.right is null) 512 found = true; 513 else 514 result = result.right; 515 }while(!found); 516 return result; 517 } 518 519 public string toString(){ 520 import std.conv; 521 string result = "Key: " ~ K.stringof ~ " : Elem: " ~ E.stringof; 522 if(root !is null) 523 result ~= root.toString(); 524 return result; 525 } 526 } 527 528 /** 529 * Implements a binary search tree without a key, meaning elements can be looked up in a different fashion, eg. through opEquals method overriding 530 */ 531 public struct BinarySearchTree2(Elem){ 532 /** 533 * Nodes for each branches. 534 */ 535 public struct Node{ 536 Elem elem; 537 Node* left; 538 Node* right; 539 @nogc this(Elem elem, Node* left = null, Node* right = null){ 540 this.elem = elem; 541 this.left = left; 542 this.right = right; 543 } 544 @nogc int opCmp(T)(ref T rhs){ 545 return this.elem.opCmp(rhs.elem); 546 } 547 /** 548 * Returns the total height. 549 */ 550 @nogc @property size_t height(){ 551 if(left is null && right is null){ 552 return 1; 553 }else{ 554 size_t l = 1, r = 1; 555 if(left !is null){ 556 l += left.height; 557 } 558 if(right !is null){ 559 r += right.height; 560 } 561 if(l >= r){ 562 return l; 563 }else{ 564 return r; 565 } 566 } 567 } 568 /** 569 * Returns the balance of the node. Minus if LHS is heavier, plus if RHS is heavier. 570 */ 571 @nogc @property sizediff_t bal(){ 572 if(left is null && right is null){ 573 return 0; 574 }else{ 575 size_t l, r; 576 if(left !is null){ 577 l = left.height; 578 } 579 if(right !is null){ 580 r = right.height; 581 } 582 return r - l; 583 } 584 } 585 /** 586 * String representation for debugging. 587 */ 588 public string toString(){ 589 import std.conv; 590 string result = "[" ~ to!string(elem) ~ ";" ~ to!string(bal) ~ ";"; 591 if(left is null){ 592 result ~= "lhs: null "; 593 }else{ 594 result ~= " lhs: " ~ left.toString; 595 } 596 if(right is null){ 597 result ~= "rhs: null "; 598 }else{ 599 result ~= " rhs: " ~ right.toString; 600 } 601 return result ~ "]"; 602 } 603 } 604 private Node* root; 605 606 private size_t nOfElements; ///Current number of elements 607 608 609 /** 610 * Gets an element without allocation. Returns E.init if key not found. 611 */ 612 public @nogc Elem lookup(K)(K key){ 613 bool found; 614 Node* crnt = root; 615 Elem result; 616 do{ 617 if(crnt is null){ 618 found = true; 619 }else if(crnt.elem == key){ 620 found = true; 621 result = crnt.elem; 622 }else if(crnt.elem > key){ 623 crnt = crnt.left; 624 }else{ 625 crnt = crnt.right; 626 } 627 }while(!found); 628 return result; 629 } 630 /** 631 * Inserts a new element with some automatic optimization. 632 * TODO: Make the optimization better. 633 */ 634 public @nogc Elem add(Elem elem){ 635 if(root is null){ 636 root = cast(Node*)malloc(Node.sizeof); 637 *root = Node(elem); 638 nOfElements++; 639 return elem; 640 } 641 if(insertAt(&root, elem)){ 642 rebalanceTree(&root); 643 nOfElements++; 644 } 645 return elem; 646 } 647 /** 648 * Rebalances a tree. 649 */ 650 public @nogc void rebalanceTree(){ 651 rebalanceTree(&root); 652 } 653 protected @nogc void rebalanceTree(Node** node){ 654 if((*node).height > 1){ 655 if((*node).bal > 1 || (*node).bal < -1){ 656 optimize(node); 657 } 658 if((*node).left !is null){ 659 rebalanceTree(&(*node).left); 660 } 661 if((*node).right !is null){ 662 rebalanceTree(&(*node).right); 663 } 664 } 665 } 666 /** 667 * Returns the number of elements in the tree. 668 */ 669 public @nogc @property size_t length(){ 670 return nOfElements; 671 } 672 /** 673 * Inserts an item at the given point. Returns true if the height of the tree have been raised. 674 */ 675 protected @nogc bool insertAt(Node** node, Elem elem){ 676 if(elem == (*node).elem){ 677 (*node).elem = elem; 678 return false; 679 }else if(elem < (*node).elem){ 680 if((*node).left is null){ 681 (*node).left = cast(Node*)malloc(Node.sizeof); 682 *(*node).left = Node(elem); 683 if((*node).right is null){ 684 return true; 685 }else{ 686 return false; 687 } 688 }else{ 689 return insertAt(&((*node).left), elem); 690 } 691 }else{ 692 if((*node).right is null){ 693 (*node).right = cast(Node*)malloc(Node.sizeof); 694 *(*node).right = Node(elem); 695 if((*node).left is null){ 696 return true; 697 }else{ 698 return false; 699 } 700 }else{ 701 return insertAt(&((*node).right), elem); 702 } 703 } 704 } 705 /** 706 * Removes an element by key. 707 */ 708 public @nogc void remove(Elem elem){ 709 bool handside; 710 Node* crnt = root; 711 Node* prev; 712 while(crnt !is null){ 713 if(crnt.elem == elem){ 714 if(crnt.left is null && crnt.right is null){ 715 free(crnt); 716 if(prev !is null){ 717 if(handside) 718 prev.right = null; 719 else 720 prev.left = null; 721 }else{ 722 root = null; 723 } 724 crnt = null; 725 nOfElements--; 726 }else if(crnt.left is null){ 727 if(prev is null){ 728 root = crnt.right; 729 }else{ 730 if(handside) 731 prev.right = crnt.right; 732 else 733 prev.left = crnt.right; 734 } 735 free(crnt); 736 crnt = null; 737 nOfElements--; 738 }else if(crnt.right is null){ 739 if(prev is null){ 740 root = crnt.left; 741 }else{ 742 if(handside) 743 prev.right = crnt.left; 744 else 745 prev.left = crnt.left; 746 } 747 free(crnt); 748 crnt = null; 749 nOfElements--; 750 }else{ 751 Node* temp; 752 if(handside){ 753 temp = findMin(prev.right); 754 }else{ 755 temp = findMax(prev.right); 756 } 757 //K tempKey = temp.key; 758 Elem tempVal = temp.elem; 759 Node* tempLHS = temp.left; 760 Node* tempRHS = temp.right; 761 remove(tempVal); 762 //crnt.key = tempKey; 763 crnt.elem = tempVal; 764 crnt.left = tempLHS; 765 crnt.right = tempRHS; 766 return; 767 } 768 }else if(crnt.elem > elem){ 769 prev = crnt; 770 handside = false; 771 crnt = crnt.left; 772 }else{ 773 prev = crnt; 774 handside = true; 775 crnt = crnt.right; 776 } 777 } 778 } 779 /** 780 * Rotates the subtree to the left by one. 781 */ 782 protected @nogc void rotateLeft(Node** node){ 783 Node* temp = *node; //save current node 784 *node = temp.right; //assign the first RHS to the root 785 temp.right = (*node).left; //assign the new root's LHS to the saved node's RHS 786 (*node).left = temp; //assign the saved node to the new root's LHS 787 } 788 /** 789 * Rotates the subtree to the right by one. 790 */ 791 protected @nogc void rotateRight(Node** node){ 792 Node* temp = *node; //save current node 793 *node = temp.left; //assign the first LHS to the root 794 temp.left = (*node).right; //assign the new root's RHS to the saved node's LHS 795 (*node).right = temp; //assign the saved node to the new root's RHS 796 } 797 /** 798 * Rotates the subtree to the right then to the left. 799 */ 800 protected @nogc void rotateRightLeft(Node** node){ 801 Node* temp = (*node).right.left; //save root.RHS.LHS 802 (*node).right.left = temp.right; //assign temp.RHS to root.RHS.LHS 803 temp.right = (*node).right; //assign root.RHS to temp.RHS 804 (*node).right = temp; //assign temp to root.RHS 805 //temp.right.bal = 0; //reset balance of temp.RHS 806 rotateLeft(node); //rotate the root to the left 807 } 808 /** 809 * Rotates the subtree to the right then to the left. 810 */ 811 protected @nogc void rotateLeftRight(Node** node){ 812 Node* temp = (*node).left.right; //save root.LHS.RHS 813 (*node).left.right = temp.left; //assign temp.LHS to root.LHS.RHS 814 temp.left = (*node).left; //assign root.LHS to temp.LHS 815 (*node).left = temp; //assign temp to root.LHS 816 //temp.left.bal = 0; //reset balance of temp.LHS 817 rotateRight(node); //rotate the root to the right 818 } 819 /** 820 * Optimizes a BinarySearchTree by distributing nodes evenly. 821 */ 822 protected @nogc void optimize(Node** node){ 823 if((*node).bal >= 2){ 824 if((*node).right.bal >= 1){ 825 rotateLeft(node); 826 }else if((*node).right.bal <= -1){ 827 rotateRightLeft(node); 828 } 829 }else if((*node).bal <= -2){ 830 if((*node).left.bal >= 1){ 831 rotateLeftRight(node); 832 }else if((*node).left.bal <= -1){ 833 rotateRight(node); 834 } 835 } 836 837 } 838 /** 839 * Finds the smallest value from the root. 840 */ 841 public @nogc Node* findMin(){ 842 bool found; 843 Node* result = root; 844 do{ 845 if(result.left is null) 846 found = true; 847 else 848 result = result.left; 849 }while(!found); 850 return result; 851 } 852 /** 853 * Finds the smallest value from the given root. 854 */ 855 public @nogc Node* findMin(Node* from){ 856 bool found; 857 Node* result = from; 858 do{ 859 if(result.left is null) 860 found = true; 861 else 862 result = result.left; 863 }while(!found); 864 return result; 865 } 866 /** 867 * Finds the largest value from the root. 868 */ 869 public @nogc Node* findMax(){ 870 bool found; 871 Node* result = root; 872 do{ 873 if(result.right is null) 874 found = true; 875 else 876 result = result.right; 877 }while(!found); 878 return result; 879 } 880 /** 881 * Finds the largest value from the given root. 882 */ 883 public @nogc Node* findMax(Node* from){ 884 bool found; 885 Node* result = from; 886 do{ 887 if(result.right is null) 888 found = true; 889 else 890 result = result.right; 891 }while(!found); 892 return result; 893 } 894 895 public string toString(){ 896 import std.conv; 897 string result = " : Elem: " ~ Elem.stringof; 898 if(root !is null) 899 result ~= root.toString(); 900 return result; 901 } 902 } 903 904 unittest{ 905 import std.stdio; 906 import std.random; 907 908 BinarySearchTree!(int,int) test0, test1; 909 //test 0: fill tree with consequential values 910 for(int i ; i < 32 ; i++){ 911 test0[i] = i; 912 } 913 writeln(test0); 914 //test 1: fill tree with random values 915 for(int i ; i < 32 ; i++){ 916 test0[rand()] = i; 917 } 918 writeln(test1); 919 }