C++ Library Extensions 2022.12.09
To help learn modern C++ programming
051-binary_tree03.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{ pre_order, in_order,
34 ascending_order = in_order, post_order, descending_order };
35
36 enum class child_status: int { left_child = -1, no_child = 0, right_child = 1};
37 private:
38
39 ElementType m_value; // node's value
40
41 mutable int m_height{1}; // the height of a node
42
43 binary_node* m_parent; // pointer to point to the parent node
44
45 node_ptr_t m_left; // left child node
46 node_ptr_t m_right; // right child node
47
48 public:
49
50 int height(bool bRecalculate = false) const
51 {
52 if(bRecalculate) // if bRecalculate is true,
53 { // we will recalculate the m_height member
54 int left_height = 1, right_height = 1;
55
56 if(this->m_left)
57 left_height += this->m_left->height(false); // false means we use cached value of m_height
58
59 if(this->m_right)
60 right_height += this->m_right->height(false); // false means we use cached value of m_height
61
62 // m_height is the greater of the two, left_height and right_height
63 this->m_height = left_height > right_height ?
64 left_height : right_height;
65 }
66
67 return this->m_height;
68 }
69
71 {
72 // the parent ptr of the current node
73 auto parent_ptr = this->m_parent;
74
75 if(parent_ptr)
76 {
77 auto old_height = parent_ptr->m_height;
78
79 if(old_height != parent_ptr->height(true))
80 {
81 parent_ptr = parent_ptr->m_parent;
82
83 while(parent_ptr)
84 {
85 parent_ptr->height(true); // true means update m_height of the parent node
86
87 parent_ptr = parent_ptr->m_parent;
88 }
89 }
90 }
91 }
92
94 {
95 if(this->m_left && this->m_left.get() == child)
96
98 else if(this->m_right && this->m_right.get() == child)
99
101 else
103 }
104
106 {
107 os << "node_" << this->m_value;
108 return os;
109 }
110
112 {
113 // node_1 [ shape=box, label = " Root "] ;
114 get_node_name(os)
115 << " [ shape=oval, label = \"V:"
116 << this->m_value
117 << " H:"<< this->m_height << "\"] ;";
118
119 return os;
120 }
121
123 {
124 get_node_definition(os) << nl;
125
126 if(this->m_parent)
127 {
128 get_node_name(os) << " -> ";
129 this->m_parent->get_node_name(os);
130
131 auto status = this->m_parent->get_child_status(this);
132
133 if(status == child_status::left_child)
134 os << " [style = dashed, color = red] ; " << nl;
135 else if (status == child_status::right_child)
136 os << " [style = dashed, color = blue] ; " << nl;
137 }
138
139 // root -> left
140 if(this->m_left)
141 {
142 get_node_name(os) << " -> ";
143 this->m_left->get_node_name(os) << " [ color = red ] ;" << nl;
144
145 // recursion for left children
146 this->m_left->print_node(os);
147 }
148
149 // root -> right
150 if(this->m_right)
151 {
152 get_node_name(os) << " -> ";
153 this->m_right->get_node_name(os) << " [color = blue ] ; " << nl;
154
155 // recursion for right children
156 this->m_right->print_node(os);
157 }
158 }
160 {
161 tpf::sstream os;
162
163 os << "digraph G { " << nl;
164
165 print_node(os);
166
167 os <<"}";
168
169 return os.str();
170 }
171
172 const ElementType& get() const { return this->m_value; }
173
174 // if find() fails, returns nullptr,
175 // if successful, it returns the pointer that points
176 // to the node that has the value
177 binary_node* find(ElementType value)
178 {
179 if(value == this->m_value)
180 return this;
181
182 binary_node* ptr = nullptr;
183
184 // recursion
185 if(this->m_left && (ptr = this->m_left->find(value)))
186 return ptr;
187 // recursion
188 if(this->m_right && (ptr = this->m_right->find(value)))
189 return ptr;
190
191 return nullptr;
192 }
193
194 binary_node(ElementType value = ElementType{}, binary_node* parent = nullptr):
195 m_value{value}, m_parent{parent} { }
196
197 // if insertion fails, returns false
198
199 template<typename Type>
200 // we enable this function only when Type and ElementType are same
202 insert(Type&& value)
203 {
204 if(value == this->m_value)
205 return false;
206 else if(value < this->m_value)
207 {
208 if(this->m_left)
209 // this is recursion
210 return this->m_left->insert(std::forward<Type>(value));
211 else
212 {
213 // a new node is inserted and set to this->m_left member
214 // new inserted node is a Leaf node.
215 this->m_left.reset(new binary_node{std::forward<Type>(value), this} );
216
217 // this call updates all m_height members of its parents
218 this->m_left->update_height();
219
220 return true;
221 }
222 }
223 else // value > this->m_value
224 {
225 if(this->m_right)
226 // this is also recursion
227 return this->m_right->insert(std::forward<Type>(value));
228 else
229 {
230 // a new node is inserted and set to this->m_right member
231 // the new inserted node is a LEAF node
232 this->m_right.reset( new binary_node{std::forward<Type>(value), this});
233
234 // update all m_height members of its parents
235 this->m_right->update_height();
236
237 return true;
238 }
239 }
240 }
241
242 // return true only if all parameters are inserted
243 // successfully, otherwise returns false
244 template<typename Type, typename... Types>
245 // we enable this function only when ElementType, Type, and Types... are
246 // of same type
247 enable_if_all_types_are_the_same_t<bool, ElementType, Type, Types...>
248 insert(Type&& arg, Types&&... args)
249 {
250 bool result = this->insert(std::forward<Type>(arg));
251
252 if constexpr(sizeof...(args) != 0)
253 {
254 // recursion
255 return result && this->insert(std::forward<Types>(args)...);
256 }
257 else
258 return result;
259 }
260
261 // for more information about visiting order
262 // Binary Tree (ALL Interview Questions)
263 // https://www.youtube.com/watch?v=VQTF_pRTZek&list=PLeIMaH7i8JDj7DnmO7lll97P1yZjMCpgY&index=2
265 {
266 switch(order)
267 {
269 {
270 os << this->m_value << nl;
271
272 if(this->m_left)
273 this->m_left->visit_nodes(os, order);
274
275 if(this->m_right)
276 this->m_right->visit_nodes(os, order);
277
278 return;
279 }
281 {
282 if(this->m_left)
283 this->m_left->visit_nodes(os, order);
284
285 if(this->m_right)
286 this->m_right->visit_nodes(os, order);
287
288 os << this->m_value << nl;
289
290 return;
291 }
292
294 {
295 if(this->m_right)
296 this->m_right->visit_nodes(os, order);
297
298 os << this->m_value << nl;
299
300 if(this->m_left)
301 this->m_left->visit_nodes(os, order);
302
303 return;
304 }
305
307 default: // in_order
308 {
309 if(this->m_left)
310 this->m_left->visit_nodes(os, order);
311
312 os << this->m_value << nl;
313
314 if(this->m_right)
315 this->m_right->visit_nodes(os, order);
316
317 return;
318 }
319 }
320 }
321};
322
324{
325 // In courtesy of Vivekanand Khyade - Algorithm Every Day
326 // Introduction to AVL tree (Why AVL tree is needed?)
327 // https://youtu.be/5Q-__zhQ2Gs?t=10
328
329 binary_node<int> root{10};
330
332
333 root.insert(8);
334 root.insert(15);
335
336 root.insert(7);
337 root.insert(9);
338 root.insert(12);
339 root.insert(17);
340
341 root.insert(6);
342 root.insert(16);
343 root.insert(18);
344
345 tpf::sstream os;
346
347 root.visit_nodes(os, visit_mode::ascending_order);
348 stream << "Ascending-order: " << endL;
349 stream << os.str() << endL;
350
351 os.clear();
352
353 root.visit_nodes(os, visit_mode::descending_order);
354 stream << "Descending-order: " << endL;
355 stream << os.str() << endL;
356}
357
359{
360 // In courtesy of Vivekanand Khyade - Algorithm Every Day
361 // Introduction to AVL tree (Why AVL tree is needed?)
362 // https://youtu.be/5Q-__zhQ2Gs?t=10
363
364 binary_node<int> root{10};
365
367
368 root.insert(8, 15, 7, 9, 12, 17, 6, 16, 18, 25);
369
370 if(auto ptr = root.find(6))
371 {
372 stream << "Value found: " << ptr->get() << endl;
373 }
374 else
375 {
376 stream <<"Value not found " << endl;
377 }
378
379 if(auto ptr = root.find(20) )
380 {
381 stream << "Value found: " << ptr->get() << endl;
382 }
383 else
384 {
385 stream << "Value not found " << endl;
386 }
387}
388
389
391{
392 // In courtesy of Vivekanand Khyade - Algorithm Every Day
393 // Introduction to AVL tree (Why AVL tree is needed?)
394 // https://youtu.be/5Q-__zhQ2Gs?t=10
395
396 binary_node<int> root{10};
397
399
400 root.insert(8, 15, 7, 9, 12, 17, 6, 16, 18);
401
402 stream << root.build_digraph() << endl;
403
404}
405
406
407int main(int argc, const char* argv[])
408{
409 // test_ascending_descending_order();
410
411 // test_find_binary_tree();
412
413 // test_build_digraph();
414
415 if(argc < 2)
416 {
417 // Introduction to AVL tree (Why AVL tree is needed?)
418 //v https://youtu.be/5Q-__zhQ2Gs?t=29
419
420 // bin_graph 10 8 15 7 9 12 17 6 16 18 > binary_tree.gv
421
422 stream << "Usage: " << argv[0] << " node list " << endl;
423 stream <<"Example: "<<argv[0] <<" 10 8 15 7 9 12 17 6 16 18 > binary_tree.gv" << endl;
424 stream << "dot -Tpng binary_tree.gv -o binary_tree.png" << endl;
425
426 return 0;
427 }
428
429 binary_node<int> root { std::atoi(argv[1])};
430
431 for(int i = 2; i < argc; ++i)
432 {
433 root.insert( std::atoi(argv[i]) );
434 }
435
436 stream << root.build_digraph() << endl;
437}
std::string string_t
auto endL
tpf::sstream stream
auto nL
auto endl
void test_ascending_descending_order()
void test_find_binary_tree()
int main(int argc, const char *argv[])
std::enable_if_t< tpf::types::is_same_v< tpf::remove_cv_ref_t< Types >... >, ReturnType > enable_if_all_types_are_the_same_t
auto nl
void test_build_digraph()
typename binary_node< ElementType >::node_ptr_t node_ptr_t
typename graph_t::visit_mode visit_mode
Definition: 060-graph02.cpp:8
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)
tpf::sstream & get_node_name(tpf::sstream &os)
string_t build_digraph()
const ElementType & get() const
void print_node(tpf::sstream &os)
std::unique_ptr< binary_node > node_ptr_t
tpf::sstream & get_node_definition(tpf::sstream &os)
bool insert(ElementType value)
enable_if_all_types_are_the_same_t< bool, ElementType, Type > insert(Type &&value)
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.