C++ Library Extensions 2022.12.09
To help learn modern C++ programming
056-binary_tree08.cpp
Go to the documentation of this file.
1#include <tpf_output.hpp>
2
3/*
4 binary_tree 50 17 72 12 23 54 76 9 14 19 67 > old.txt
5
6 binary_tree 50 17 72 12 23 54 76 9 14 19 67 25 > new.txt
7
8 binary_tree 50 17 72 12 23 54 76 9 14 19 67 25 18> newnew.txt
9
10 https://edotor.net/
11
12 */
13
15
16auto endl = tpf::endl; // single carriage return and flush to console output
17auto endL = tpf::endL; // double carriage returns and flush to console output
18
19auto nl = tpf::nl; // single carriage return without flush
20auto nL = tpf::nL; // double carriage returns without flush
21
22using string_t = std::string;
23
24template<typename ReturnType, typename... Types>
26 std::enable_if_t<tpf::types::is_same_v<tpf::remove_cv_ref_t<Types>...>, ReturnType>;
27
28template<typename ElementType>
29class binary_node
30{
31 public:
32 using node_ptr_t = std::unique_ptr<binary_node>;
33 enum class visit_mode: int{ undefined = 0, pre_order, in_order,
34 ascending_order = in_order, post_order, descending_order };
35
36 enum class find_mode: int { undefined = 0, predecessor = 1, exact_match = 2, successor = 3 };
37
38 enum class child_status: int { left_child = -1, no_child = 0, right_child = 1};
39 private:
40
41 ElementType m_value; // node's value
42
43 mutable int m_height{1}; // the height of a node
44
45 binary_node* m_parent; // pointer to point to the parent node
46
47 node_ptr_t m_left; // left child node
48 node_ptr_t m_right; // right child node
49
50 public:
51
52 int height(bool bRecalculate = false) const
53 {
54 if(bRecalculate) // if bRecalculate is true,
55 { // we will recalculate the m_height member
56 int left_height = 1, right_height = 1;
57
58 if(this->m_left)
59 left_height += this->m_left->height(false); // false means we use cached value of m_height
60
61 if(this->m_right)
62 right_height += this->m_right->height(false); // false means we use cached value of m_height
63
64 // m_height is the greater of the two, left_height and right_height
65 this->m_height = left_height > right_height ?
66 left_height : right_height;
67 }
68
69 return this->m_height;
70 }
71
73 {
74 // the parent ptr of the current node
75 auto parent_ptr = this->m_parent;
76
77 while(parent_ptr)
78 {
79 auto old_height = parent_ptr->m_height;
80
81 if(old_height != parent_ptr->height(true))
82 parent_ptr = parent_ptr->m_parent;
83 else
84 break;
85 }
86 }
87
89 {
90 if(this->m_left && this->m_left.get() == child)
91
93 else if(this->m_right && this->m_right.get() == child)
94
96 else
98 }
99
101 {
102 os << "node_" << this->m_value;
103 return os;
104 }
105
107 {
108 // node_1 [ shape=box, label = " Root "] ;
109 get_node_name(os)
110 << " [ shape=oval, label = \"V: "
111 << this->m_value
112 << " H:"<< this->m_height << " \"] ;";
113
114 return os;
115 }
116
118 {
119 get_node_definition(os) << nl;
120
121 if(this->m_parent)
122 {
123 get_node_name(os) << " -> ";
124 this->m_parent->get_node_name(os);
125
126 auto status = this->m_parent->get_child_status(this);
127
128 if(status == child_status::left_child)
129 os << " [style = dashed, color = red] ; " << nl;
130 else if (status == child_status::right_child)
131 os << " [style = dashed, color = blue] ; " << nl;
132 }
133
134 // root -> left
135 if(this->m_left)
136 {
137 get_node_name(os) << " -> ";
138 this->m_left->get_node_name(os) << " [ color = red ] ;" << nl;
139
140 // recursion for left children
141 this->m_left->print_node(os);
142 }
143
144 // root -> right
145 if(this->m_right)
146 {
147 get_node_name(os) << " -> ";
148 this->m_right->get_node_name(os) << " [color = blue ] ; " << nl;
149
150 // recursion for right children
151 this->m_right->print_node(os);
152 }
153 }
155 {
156 tpf::sstream os;
157
158 os << "digraph G { " << nl;
159
160 print_node(os);
161
162 os <<"}";
163
164 return os.str();
165 }
166
167 const ElementType& get() const { return this->m_value; }
168
169 // if value is not found,
170 // this function returns nullptr
171 void find_raw(ElementType value)
172 {
173 if(value < this->m_value)
174 {
175 if(this->m_left) this->m_left->find_raw(value);
176 }
177 else if (value > this->m_value)
178 {
179 if(this->m_right) this->m_right->find_raw(value);
180 }
181 else
182 {
183 throw this;
184 }
185 }
186
187 binary_node* find(ElementType value)
188 {
189 try
190 {
191 this->find_raw(value);
192 return nullptr;
193 }
194 catch(binary_node* ptr)
195 {
196 return ptr;
197 }
198 }
199
201 {
202 if(this->m_left)
203 return this->m_left->minimum();
204 else
205 return this;
206 }
207
209 {
210 if(this->m_right)
211 return this->m_right->maximum();
212 else
213 return this;
214 }
215
216 binary_node(ElementType value = ElementType{}, binary_node* parent = nullptr):
217 m_value{value}, m_parent{parent} { }
218
219 // if insertion fails, returns false
220
221 template<typename Type>
222 // we enable this function only when Type and ElementType are same
224 insert(Type&& value)
225 {
226 if(value == this->m_value)
227 return false;
228 else if(value < this->m_value)
229 {
230 if(this->m_left)
231 // this is recursion
232 return this->m_left->insert(std::forward<Type>(value));
233 else
234 {
235 // a new node is inserted and set to this->m_left member
236 // new inserted node is a Leaf node.
237 this->m_left.reset(new binary_node{std::forward<Type>(value), this} );
238
239 // this call updates all m_height members of its parents
240 this->m_left->update_height();
241
242 return true;
243 }
244 }
245 else // value > this->m_value
246 {
247 if(this->m_right)
248 // this is also recursion
249 return this->m_right->insert(std::forward<Type>(value));
250 else
251 {
252 // a new node is inserted and set to this->m_right member
253 // the new inserted node is a LEAF node
254 this->m_right.reset( new binary_node{std::forward<Type>(value), this});
255
256 // update all m_height members of its parents
257 this->m_right->update_height();
258
259 return true;
260 }
261 }
262 }
263
264 // node_ptr_t == std::unique_ptr<binary_node>
265 bool graft(node_ptr_t& node_ptr)
266 {
267 if(node_ptr->m_value < this->m_value)
268 {
269 if(this->m_left)
270 // this is recursion
271 return this->m_left->graft(node_ptr);
272 else
273 {
274 node_ptr->m_parent = this;
275 this->m_left = std::move(node_ptr);
276 this->m_left->update_height();
277
278 return true;
279 }
280 }
281 else // node_ptr->m_value > this->m_value
282 {
283 if(this->m_right)
284 // this is also recursion
285 return this->m_right->graft(node_ptr);
286 else
287 {
288 node_ptr->m_parent = this;
289 this->m_right = std::move(node_ptr);
290 this->m_right->update_height();
291
292 return true;
293 }
294 }
295 }
296
297 // return true only if all parameters are inserted
298 // successfully, otherwise returns false
299 template<typename Type, typename... Types>
300 // we enable this function only when ElementType, Type, and Types... are
301 // of same type
302 enable_if_all_types_are_the_same_t<bool, ElementType, Type, Types...>
303 insert(Type&& arg, Types&&... args)
304 {
305 bool result = this->insert(std::forward<Type>(arg));
306
307 if constexpr(sizeof...(args) != 0)
308 {
309 // recursion
310 return result && this->insert(std::forward<Types>(args)...);
311 }
312 else
313 return result;
314 }
315
316 // for more information about visiting order
317 // Binary Tree (ALL Interview Questions)
318 // https://www.youtube.com/watch?v=VQTF_pRTZek&list=PLeIMaH7i8JDj7DnmO7lll97P1yZjMCpgY&index=2
320 {
321 switch(order)
322 {
324 {
325 os << this->m_value << ", ";
326
327 if(this->m_left)
328 this->m_left->visit_nodes(os, order);
329
330 if(this->m_right)
331 this->m_right->visit_nodes(os, order);
332
333 return;
334 }
336 {
337 if(this->m_left)
338 this->m_left->visit_nodes(os, order);
339
340 if(this->m_right)
341 this->m_right->visit_nodes(os, order);
342
343 os << this->m_value << ", ";
344
345 return;
346 }
347
349 {
350 if(this->m_right)
351 this->m_right->visit_nodes(os, order);
352
353 os << this->m_value << ", ";
354
355 if(this->m_left)
356 this->m_left->visit_nodes(os, order);
357
358 return;
359 }
360
362 default: // in_order
363 {
364 if(this->m_left)
365 this->m_left->visit_nodes(os, order);
366
367 os << this->m_value << ", ";
368
369 if(this->m_right)
370 this->m_right->visit_nodes(os, order);
371
372 return;
373 }
374 }
375 }
376
377 // if fails, return nullptr
378 binary_node* find(ElementType value, find_mode fmode,
380 {
381 binary_node* ptr = nullptr;
382
383 if(((vmode==visit_mode::ascending_order) && (fmode==find_mode::successor))||
385 {
386 if(this->m_left && (ptr = this->m_left->find(value, fmode, vmode)))
387 return ptr;
388
389 if( value < this->m_value)
390 return this;
391
392 if(this->m_right && (ptr = this->m_right->find(value, fmode, vmode)))
393 return ptr;
394
395 // we failed
396 return ptr;
397 }
398 else if(( (vmode == visit_mode::ascending_order)&&(fmode==find_mode::predecessor)) ||
400 {
401 if(this->m_right && (ptr = this->m_right->find(value, fmode, vmode)))
402 return ptr;
403
404 if(value > this->m_value)
405 return this;
406
407 if(this->m_left && (ptr = this->m_left->find(value, fmode, vmode)))
408 return ptr;
409
410 return ptr;
411 }
412 else if(fmode == find_mode::exact_match)
413 return this->find(value);
414 else
415 return nullptr;
416 }
417
419 {
420 // both m_left and m_right are nullptr
421 return (!this->m_left && !this->m_right);
422 }
423
425 {
426 if(this->m_left && (ptr == this->m_left.get()))
427 return std::move(this->m_left);
428 else if(this->m_right && (ptr == this->m_right.get()))
429 return std::move(this->m_right);
430 else
431 return nullptr;
432 }
433
434 static bool remove_node(node_ptr_t& root_ptr, ElementType value)
435 {
436 binary_node* ptr = root_ptr->find(value);
437
438 // node with "value" does not exist
439 if(!ptr) return false;
440
441 // if parent is nullptr, then it is root node
442 if(!ptr->m_parent)
443 {
444 // ptr is a root node of type binary_node*
445 // root_ptr is a root node of type
446 // std::unique_ptr<binary_node>;
447
448 // we move left child to left_child
449 // after move, root_ptr->m_left is invalid
450 node_ptr_t left_child
451 = std::move(root_ptr->m_left);
452
453 // after move, root_ptr->m_right is invalid
454 node_ptr_t right_child
455 = std::move(root_ptr->m_right);
456
457 if(right_child) // new root
458 {
459 // because root node does not have its parent.
460 right_child->m_parent = nullptr;
461
462 // existing root_ptr is destroyed
463 // and right_child is moved to root_ptr
464 // at this point, existing old root is
465 // properly released.
466 root_ptr = std::move(right_child);
467
468 // do not forget this part
469 if(left_child)
470 root_ptr->graft(left_child);
471
472 return true;
473 }
474 else if(left_child) // right_child is nullptr
475 // left_child is a new root.
476 {
477 // because root node does not have its parent.
478 left_child->m_parent = nullptr;
479
480 // after move, the older root is released
481 // and left_child is moved to root_ptr
482 root_ptr = std::move(left_child);
483
484 return true;
485 }
486 else
487 {
488 // since we destroyed the root
489 // we should not access the root after this statment
490 root_ptr.reset();
491
492 return true;
493 }
494 }
495 else // non-root node
496 {
497 // ptr is the node to remove
498 // is not a root node.
499
500 if(ptr->is_leaf_node())
501 {
502 // this code cuts off the relation
503 // between the child node and its parent.
504 node_ptr_t orphan =
505 ptr->m_parent->release_child(ptr);
506
507 // when the orphan goes off this block,
508 // the allocated memory for orphan is
509 // cleaned up. and orphan.get() == ptr
510
511 if(ptr->m_parent->is_leaf_node())
512 {
513 ptr->m_parent->m_height = 1;
514 ptr->m_parent->update_height();
515 }
516
517 return true;
518 }
519 else // not a leaf node,
520 {
521 // cut off the relationship between ptr
522 // and its parent.
523 node_ptr_t orphan =
524 ptr->m_parent->release_child(ptr);
525
526 // this is for update the height of the parents
527 // nodes
528 ptr->m_parent->height(true);
529 ptr->m_parent->update_height();
530
531 node_ptr_t left_child =
532 std::move(orphan->m_left);
533
534 node_ptr_t right_child =
535 std::move(orphan->m_right);
536
537 if(right_child)
538 root_ptr->graft(right_child);
539
540 if(left_child)
541 root_ptr->graft(left_child);
542
543 return true;
544 }
545 }
546 }
547}; // end of binary_node class
548
549// std::unique_ptr<binary_node<ElementType>>
550template<typename ElementType>
552
553template<typename ElementType>
554void test_remove_node(node_ptr_t<ElementType>& node_ptr, ElementType value)
555{
556 using binary_node_t = binary_node<ElementType>;
557 using node_ptr_t = std::unique_ptr<binary_node_t>;
558
559 binary_node_t::remove_node(node_ptr, value);
560
561 if(node_ptr)
562 {
563 stream << node_ptr->build_digraph() << endl;
564 }
565
566}
567
569{
570 // In courtesy of Vivekanand Khyade - Algorithm Every Day
571 // Introduction to AVL tree (Why AVL tree is needed?)
572 // https://youtu.be/5Q-__zhQ2Gs?t=10
573
574 binary_node<int> root{10};
575
577
578 root.insert(8);
579 root.insert(15);
580
581 root.insert(7);
582 root.insert(9);
583 root.insert(12);
584 root.insert(17);
585
586 root.insert(6);
587 root.insert(16);
588 root.insert(18);
589
590 tpf::sstream os;
591
592 root.visit_nodes(os, visit_mode::ascending_order);
593 stream << "Ascending-order: " << endL;
594 stream << os.str() << endL;
595
596 os.clear();
597
598 root.visit_nodes(os, visit_mode::descending_order);
599 stream << "Descending-order: " << endL;
600 stream << os.str() << endL;
601}
602
604{
605 // In courtesy of Vivekanand Khyade - Algorithm Every Day
606 // Introduction to AVL tree (Why AVL tree is needed?)
607 // https://youtu.be/5Q-__zhQ2Gs?t=10
608
609 binary_node<int> root{10};
610
612
613 root.insert(8, 15, 7, 9, 12, 17, 6, 16, 18, 25);
614
615 if(auto ptr = root.find(6))
616 {
617 stream << "Value found: " << ptr->get() << endl;
618 }
619 else
620 {
621 stream <<"Value not found " << endl;
622 }
623
624 if(auto ptr = root.find(20) )
625 {
626 stream << "Value found: " << ptr->get() << endl;
627 }
628 else
629 {
630 stream << "Value not found " << endl;
631 }
632}
633
634
636{
637 // In courtesy of Vivekanand Khyade - Algorithm Every Day
638 // Introduction to AVL tree (Why AVL tree is needed?)
639 // https://youtu.be/5Q-__zhQ2Gs?t=10
640
641 binary_node<int> root{10};
642
644
645 root.insert(8, 15, 7, 9, 12, 17, 6, 16, 18);
646
647 stream << root.build_digraph() << endl;
648
649}
650
651void print_usage(string_t appname, const char* msg)
652{
653 stream << "Message: " << msg << endL;
654
655 stream << "Usage 1: " << appname << " graph node_list " << endL;
656 stream << "\tExample: " << appname <<" graph 10 8 15 7 9 12 17 6 16 18 > binary_tree.gv" << endL;
657 stream << "\tdot -Tpng binary_tree.gv -o binary_tree.png" << endL;
658
659 stream << "Usage 2: " << appname << " list node_list " << endL;
660 stream << "\tExample: " << appname <<" list 10 8 15 7 9 12 17 6 16 18" << endL;
661
662 stream << "Usage 3: " << appname << " {ascending|desecnding} {successor_of|predecessor_of|exact_match_of} value node_list " << endL;
663 stream << "\tExample: " << appname <<" ascending successor_of 19 10 8 15 7 9 12 17 6 16 18" << endL;
664 stream << "\t\t" <<" Finds the successor of 19 in ascending order from the list 10 8 15 7 9 12 17 6 16 18" << endL;
665
666 stream << "Usage 4: " << appname << " remove value node_list " << endL;
667 stream << "\tExample: " << appname <<" remove 19 10 8 15 7 9 12 17 6 16 18" << endL;
668 stream << "\t\t" <<" Find and remove node with value 19 from the list 10 8 15 7 9 12 17 6 16 18" << endL;
669
670 stream << "Usage 5: " << appname << " find value node_list " << endL;
671 stream << "\tExample: " << appname <<" find 19 10 8 15 7 9 12 17 6 16 18" << endL;
672 stream << "\t\t" <<" Find 19 from the list 10 8 15 7 9 12 17 6 16 18" << endL;
673
674 stream << "Usage 6: " << appname << " min_max node_list " << endL;
675 stream << "\tExample: " << appname <<" min_max 10 8 15 7 9 12 17 6 16 18" << endL;
676 stream << "\t\t" <<" Find minimum and maximum from the list 10 8 15 7 9 12 17 6 16 18" << endL;
677}
678
679int main(int argc, const char* argv[])
680{
681 // test_ascending_descending_order();
682 // test_find_binary_tree();
683 // test_build_digraph();
684
685 string_t appname{argv[0]};
686
687 if(argc < 2)
688 {
689 print_usage(appname, "Program commandline syntax");
690
691 return 0;
692 }
693
694 string_t command{argv[1]};
695
696 if(command == "graph")
697 {
698 binary_node<int> root { std::atoi(argv[2])};
699
700 for(int i = 3; i < argc; ++i)
701 {
702 root.insert( std::atoi(argv[i]) );
703 }
704
705 stream << root.build_digraph() << endl;
706 }
707 else if(command == "list")
708 {
709 binary_node<int> root { std::atoi(argv[2])};
711
712 for(int i = 3; i < argc; ++i)
713 {
714 root.insert( std::atoi(argv[i]) );
715 }
716
717 stream <<"Ascending order: ";
718 root.visit_nodes(stream, visit_mode::ascending_order);
719 stream << endl;
720
721 stream <<"Descending order: ";
722 root.visit_nodes(stream, visit_mode::descending_order);
723 stream << endl;
724 }
725 else if(command == "ascending"
726 || command == "descending")
727 {
729 using find_mode = binary_node<int>::find_mode;
730
731 visit_mode vmode {visit_mode::undefined};
732 find_mode fmode {find_mode::undefined};
733
734 if(command == "ascending")
735 vmode = visit_mode::ascending_order;
736
737 if(command == "descending")
738 vmode = visit_mode::descending_order;
739
740 if(vmode==visit_mode::undefined)
741 {
742 print_usage(appname, "Undefined visit mode");
743 return 0;
744 }
745
746 if(argc < 5)
747 {
748 print_usage(appname, "Syntax Error");
749 return 0;
750 }
751
752 string_t operation{argv[2]};
753
754 if(operation == "successor_of")
755 fmode = find_mode::successor;
756
757 if(operation == "predecessor_of")
758 fmode = find_mode::predecessor;
759
760 if(operation == "exact_match_of")
761 fmode = find_mode::exact_match;
762
763 if(fmode == find_mode::undefined)
764 {
765 print_usage(appname, "Undefined find mode");
766 return 0;
767 }
768
769 int value = std::atoi(argv[3]);
770
771 binary_node<int> root { std::atoi(argv[4])};
773
774 for(int i = 5; i < argc; ++i)
775 {
776 root.insert( std::atoi(argv[i]) );
777 }
778
779 stream <<"Ascending order: ";
780 root.visit_nodes(stream, visit_mode::ascending_order);
781 stream << endl;
782
783 stream <<"Descending order: ";
784 root.visit_nodes(stream, visit_mode::descending_order);
785 stream << endl;
786
787 auto ptr = root.find(value, fmode, vmode);
788
789 if(ptr)
790 {
791 if(fmode == find_mode::successor)
792 stream << "The successor of " << value;
793 else if (fmode == find_mode::predecessor)
794 stream << "The predecessor of " << value;
795 else if (fmode == find_mode::exact_match)
796 stream << "The exact match of " << value;
797
798 if(vmode == visit_mode::ascending_order)
799 stream << " in ascending order is ";
800
801 if(vmode == visit_mode::descending_order)
802 stream << " in descending order is ";
803
804 stream << ptr->get() << endL;
805 }
806 else
807 {
808 if(fmode == find_mode::successor)
809 stream << "The successor of " << value;
810 else if (fmode == find_mode::predecessor)
811 stream << "The predecessor of " << value;
812 else if (fmode == find_mode::exact_match)
813 stream << "The exact match of " << value;
814
815 if(vmode == visit_mode::ascending_order)
816 stream << " in ascending order is NOT found";
817
818 if(vmode == visit_mode::descending_order)
819 stream << " in descending order NOT found ";
820
821 stream << endL;
822 }
823 }
824 else if(command == "remove")
825 {
826 using binary_node_t = binary_node<int>;
827 using node_ptr_t = std::unique_ptr<binary_node_t>;
828
829 // binary_tree remove 10 10
830 if(argc < 4)
831 {
832 print_usage(appname, "Syntax Error");
833 return 0;
834 }
835
836 int value = std::atoi(argv[2]);
837
838 node_ptr_t root = std::make_unique<binary_node_t>(std::atoi(argv[3]));
839
840 for(int i = 4; i < argc; ++i)
841 {
842 root->insert( std::atoi(argv[i]) );
843 }
844
845 test_remove_node(root, value);
846 }
847 else if(command == "find")
848 {
849 using binary_node_t = binary_node<int>;
850 using node_ptr_t = std::unique_ptr<binary_node_t>;
851
852 // binary_tree remove 10 10
853 if(argc < 4)
854 {
855 print_usage(appname, "Syntax Error");
856 return 0;
857 }
858
859 int value = std::atoi(argv[2]);
860
861 node_ptr_t root = std::make_unique<binary_node_t>(std::atoi(argv[3]));
862
863 for(int i = 4; i < argc; ++i)
864 {
865 root->insert( std::atoi(argv[i]) );
866 }
867
868 binary_node_t* ptr = root->find(value);
869
870 if(ptr)
871 {
872 stream << "We found value: " << value << endl;
873 }
874 else
875 {
876 stream << "We failed to find the value: " << value << endl;
877 }
878 }
879
880 else if(command == "min_max")
881 {
882 using binary_node_t = binary_node<int>;
883 using node_ptr_t = std::unique_ptr<binary_node_t>;
884
885 // binary_tree min_max 10 12
886 if(argc < 3)
887 {
888 print_usage(appname, "Syntax Error");
889 return 0;
890 }
891
892 node_ptr_t root = std::make_unique<binary_node_t>(std::atoi(argv[2]));
893
894 for(int i = 3; i < argc; ++i)
895 {
896 root->insert( std::atoi(argv[i]) );
897 }
898
899 binary_node_t* ptr_min = root->minimum();
900
901 if(ptr_min)
902 {
903 stream << "We found minim value: " << ptr_min->get() << endl;
904 }
905 else
906 {
907 stream << "We failed to find minimum value " << endl;
908 }
909
910
911 binary_node_t* ptr_max = root->maximum();
912
913 if(ptr_min)
914 {
915 stream << "We found maximum value: " << ptr_max->get() << endl;
916 }
917 else
918 {
919 stream << "We failed to find maximum value " << endl;
920 }
921 }
922}
std::string string_t
std::enable_if_t< tpf::types::is_same_v< tpf::remove_cv_ref_t< Types >... >, ReturnType > enable_if_all_types_are_the_same_t
typename binary_node< ElementType >::node_ptr_t node_ptr_t
auto endL
tpf::sstream stream
auto nL
void test_remove_node(node_ptr_t< ElementType > &node_ptr, ElementType value)
void print_usage(string_t appname, const char *msg)
auto endl
void test_ascending_descending_order()
void test_find_binary_tree()
int main(int argc, const char *argv[])
auto nl
void test_build_digraph()
typename graph_t::visit_mode visit_mode
Definition: 060-graph02.cpp:8
static bool remove_node(node_ptr_t &root_ptr, ElementType value)
binary_node * find(ElementType value)
enable_if_all_types_are_the_same_t< bool, ElementType, Type, Types... > insert(Type &&arg, Types &&... args)
child_status get_child_status(binary_node *child)
void find_raw(ElementType value)
tpf::sstream & get_node_name(tpf::sstream &os)
bool graft(node_ptr_t &node_ptr)
ElementType get() const
string_t build_digraph()
const ElementType & get() const
node_ptr_t release_child(binary_node *ptr)
binary_node * maximum()
void print_node(tpf::sstream &os)
std::unique_ptr< binary_node > node_ptr_t
tpf::sstream & get_node_definition(tpf::sstream &os)
binary_node * minimum()
bool insert(ElementType value)
enable_if_all_types_are_the_same_t< bool, ElementType, Type > insert(Type &&value)
binary_node * find(ElementType value, find_mode fmode, visit_mode vmode=visit_mode::ascending_order)
binary_node(ElementType value=ElementType{}, binary_node *parent=nullptr)
int height(bool bRecalculate=false) const
void visit_nodes(tpf::sstream &os, visit_mode order=visit_mode::in_order)
std::string str() const
Definition: tpf_output.hpp:951
string_stream & clear()
Definition: tpf_output.hpp:916
constexpr auto endL
Definition: tpf_output.hpp:974
constexpr auto nL
Definition: tpf_output.hpp:972
constexpr auto endl
Definition: tpf_output.hpp:973
constexpr auto nl
Definition: tpf_output.hpp:971
Stream output operators << are implemented.