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 }