CPPX 2.1.0
A Modern C++ Utility Library
Loading...
Searching...
No Matches
binary_tree.tpp
Go to the documentation of this file.
1#pragma once
2#include "../include/cppx.h"
3
4namespace stl_ext
5{
6
7template <typename T> void BinaryTree<T>::destroy_subtree(Node<T> *node)
8{
9 if (!node)
10 return;
11 std::stack<Node<T> *> s;
12 s.push(node);
13 while (!s.empty())
14 {
15 Node<T> *curr = s.top();
16 s.pop();
17 if (curr->p_left)
18 s.push(curr->p_left);
19 if (curr->p_right)
20 s.push(curr->p_right);
21 m_pool.deallocate(curr);
22 }
23}
24
25template <typename T> Node<T> *BinaryTree<T>::clone_subtree(const Node<T> *node)
26{
27 if (!node)
28 return nullptr;
29
30 struct StackEntry
31 {
32 const Node<T> *src;
34 int stage;
35 };
36
37 Node<T> *new_root = m_pool.allocate(node->m_data);
38 new_root->m_height = node->m_height;
39 new_root->m_color = node->m_color;
40
41 std::stack<StackEntry> s;
42 s.push({node, new_root, 0});
43
44 while (!s.empty())
45 {
46 auto &top = s.top();
47 if (top.stage == 0)
48 {
49 top.stage = 1;
50 if (top.src->p_left)
51 {
52 Node<T> *child = m_pool.allocate(top.src->p_left->m_data);
53 child->m_height = top.src->p_left->m_height;
54 child->m_color = top.src->p_left->m_color;
55 child->p_parent = top.dest;
56 top.dest->p_left = child;
57 s.push({top.src->p_left, child, 0});
58 }
59 }
60 else if (top.stage == 1)
61 {
62 top.stage = 2;
63 if (top.src->p_right)
64 {
65 Node<T> *child = m_pool.allocate(top.src->p_right->m_data);
66 child->m_height = top.src->p_right->m_height;
67 child->m_color = top.src->p_right->m_color;
68 child->p_parent = top.dest;
69 top.dest->p_right = child;
70 s.push({top.src->p_right, child, 0});
71 }
72 }
73 else
74 {
75 s.pop();
76 }
77 }
78
79 return new_root;
80}
81
82template <typename T> BinaryTree<T>::BinaryTree(const BinaryTree &other) : p_head(nullptr)
83{
84 p_head = clone_subtree(other.p_head);
85}
86
88{
89 if (this == &other)
90 return *this;
91 destroy_subtree(p_head);
92 p_head = nullptr;
93 m_pool.destroy_all();
94 p_head = clone_subtree(other.p_head);
95 return *this;
96}
97
98template <typename T>
99BinaryTree<T>::BinaryTree(BinaryTree &&other) noexcept : p_head(other.p_head), m_pool(std::move(other.m_pool))
100{
101 other.p_head = nullptr;
102}
103
104template <typename T> BinaryTree<T> &BinaryTree<T>::operator=(BinaryTree &&other) noexcept
105{
106 if (this == &other)
107 return *this;
108 destroy_subtree(p_head);
109 p_head = other.p_head;
110 m_pool = std::move(other.m_pool);
111 other.p_head = nullptr;
112 return *this;
113}
114
115template <typename T> BinaryTree<T>::~BinaryTree()
116{
117 p_head = nullptr;
118}
119
120template <typename T> void BinaryTree<T>::preorder(const Node<T> *node) const
121{
122 if (!node)
123 return;
124 std::stack<const Node<T> *> s;
125 s.push(node);
126 while (!s.empty())
127 {
128 const Node<T> *curr = s.top();
129 s.pop();
130 std::cout << curr->m_data << " ";
131 if (curr->p_right)
132 s.push(curr->p_right);
133 if (curr->p_left)
134 s.push(curr->p_left);
135 }
136}
137
138template <typename T> void BinaryTree<T>::inorder(const Node<T> *node) const
139{
140 std::stack<const Node<T> *> s;
141 const Node<T> *curr = node;
142 while (curr || !s.empty())
143 {
144 while (curr)
145 {
146 s.push(curr);
147 curr = curr->p_left;
148 }
149 curr = s.top();
150 s.pop();
151 std::cout << curr->m_data << " ";
152 curr = curr->p_right;
153 }
154}
155
156template <typename T> void BinaryTree<T>::postorder(const Node<T> *node) const
157{
158 if (!node)
159 return;
160 std::stack<const Node<T> *> s;
161 const Node<T> *curr = node;
162 const Node<T> *last = nullptr;
163 while (!s.empty() || curr)
164 {
165 if (curr)
166 {
167 s.push(curr);
168 curr = curr->p_left;
169 }
170 else
171 {
172 const Node<T> *peek = s.top();
173 if (peek->p_right && last != peek->p_right)
174 curr = peek->p_right;
175 else
176 {
177 std::cout << peek->m_data << " ";
178 last = peek;
179 s.pop();
180 }
181 }
182 }
183}
184
185template <typename T> void BinaryTree<T>::levelorder(const Node<T> *node) const
186{
187 if (!node)
188 return;
189 std::queue<const Node<T> *> q;
190 q.push(node);
191 while (!q.empty())
192 {
193 const Node<T> *cur = q.front();
194 q.pop();
195 std::cout << cur->m_data << " ";
196 if (cur->p_left)
197 q.push(cur->p_left);
198 if (cur->p_right)
199 q.push(cur->p_right);
200 }
201}
202
203template <typename T> int BinaryTree<T>::compute_size(const Node<T> *node) const
204{
205 if (!node)
206 return 0;
207 int c = 0;
208 std::queue<const Node<T> *> q;
209 q.push(node);
210 while (!q.empty())
211 {
212 const Node<T> *curr = q.front();
213 q.pop();
214 c++;
215 if (curr->p_left)
216 q.push(curr->p_left);
217 if (curr->p_right)
218 q.push(curr->p_right);
219 }
220 return c;
221}
222
223template <typename T> Node<T> *BinaryTree<T>::get_root() const
224{
225 return p_head;
226}
227
228template <typename T> void BinaryTree<T>::set_root(Node<T> *root)
229{
230 if (p_head && root != p_head)
231 {
232 destroy_subtree(p_head);
233 }
234 p_head = root;
235}
236
237template <typename T> bool BinaryTree<T>::is_empty() const
238{
239 return p_head == nullptr;
240}
241
242template <typename T> int BinaryTree<T>::size() const
243{
244 return compute_size(p_head);
245}
246
247template <typename T> void BinaryTree<T>::set_left(Node<T> *p, Node<T> *l)
248{
249 if (p)
250 {
251 if (p->p_left)
252 destroy_subtree(p->p_left);
253 p->p_left = l;
254
255 int h_left = p->p_left ? p->p_left->m_height : 0;
256 int h_right = p->p_right ? p->p_right->m_height : 0;
257 p->m_height = static_cast<std::int8_t>(1 + std::max(h_left, h_right));
258 }
259}
260
261template <typename T> void BinaryTree<T>::set_right(Node<T> *p, Node<T> *r)
262{
263 if (p)
264 {
265 if (p->p_right)
266 destroy_subtree(p->p_right);
267 p->p_right = r;
268
269 int h_left = p->p_left ? p->p_left->m_height : 0;
270 int h_right = p->p_right ? p->p_right->m_height : 0;
271 p->m_height = static_cast<std::int8_t>(1 + std::max(h_left, h_right));
272 }
273}
274
275template <typename T> void BinaryTree<T>::print_preorder() const
276{
277 preorder(p_head);
278 std::cout << std::endl;
279}
280template <typename T> void BinaryTree<T>::print_inorder() const
281{
282 inorder(p_head);
283 std::cout << std::endl;
284}
285template <typename T> void BinaryTree<T>::print_postorder() const
286{
287 postorder(p_head);
288 std::cout << std::endl;
289}
290template <typename T> void BinaryTree<T>::print_levelorder() const
291{
292 levelorder(p_head);
293 std::cout << std::endl;
294}
295
296template <typename T> Node<T> *BinaryTree<T>::make_node(const T &val)
297{
298 return m_pool.allocate(val);
299}
300
301template <typename T> Node<T> *BinaryTree<T>::make_node(const T &val, Node<T> *l, Node<T> *r)
302{
303 return m_pool.allocate(val, l, r);
304}
305
306template <typename T>
307void BinaryTree<T>::print_tree_helper(const Node<T> *node, const std::string &prefix, bool is_left) const
308{
309 if (!node)
310 return;
311
312 print_tree_helper(node->p_right, prefix + (is_left ? "\u2502 " : " "), false);
313
314 std::cout << prefix << (is_left ? "\u2514\u2500\u2500 " : "\u250c\u2500\u2500 ") << node->m_data << "\n";
315
316 print_tree_helper(node->p_left, prefix + (is_left ? " " : "\u2502 "), true);
317}
318
319template <typename T> void BinaryTree<T>::print_tree() const
320{
321 if (!p_head)
322 {
323 std::cout << "(empty tree)" << std::endl;
324 return;
325 }
326
327 print_tree_helper(p_head->p_right, " ", false);
328
329 std::cout << p_head->m_data << "\n";
330
331 print_tree_helper(p_head->p_left, " ", true);
332
333 std::cout << std::flush;
334}
335
336template <typename T> void BinaryTree<T>::dot_helper(const Node<T> *node, std::ostream &out, int &null_count) const
337{
338 if (!node)
339 return;
340
341 if (node->p_left)
342 {
343 out << " \"" << node->m_data << "\" -> \"" << node->p_left->m_data << "\";\n";
344 dot_helper(node->p_left, out, null_count);
345 }
346 else
347 {
348 out << " null" << null_count << " [shape=point];\n";
349 out << " \"" << node->m_data << "\" -> null" << null_count << ";\n";
350 ++null_count;
351 }
352
353 if (node->p_right)
354 {
355 out << " \"" << node->m_data << "\" -> \"" << node->p_right->m_data << "\";\n";
356 dot_helper(node->p_right, out, null_count);
357 }
358 else
359 {
360 out << " null" << null_count << " [shape=point];\n";
361 out << " \"" << node->m_data << "\" -> null" << null_count << ";\n";
362 ++null_count;
363 }
364}
365
366template <typename T> void BinaryTree<T>::dump_to_dot(const std::string &filename) const
367{
368 std::ofstream out(filename);
369 if (!out.is_open())
370 {
371 throw std::runtime_error("Could not open file: " + filename);
372 }
373
374 out << "digraph BST {\n";
375 out << " node [shape=circle];\n";
376
377 if (p_head)
378 {
379 int null_count = 0;
380 dot_helper(p_head, out, null_count);
381 }
382
383 out << "}\n";
384 out.close();
385}
386
387} // namespace stl_ext
int compute_size(const Node< T > *node) const
void print_levelorder() const
void destroy_subtree(Node< T > *node)
Node< T > * clone_subtree(const Node< T > *node)
void set_right(Node< T > *parent, Node< T > *right_child)
void postorder(const Node< T > *node) const
void set_left(Node< T > *parent, Node< T > *left_child)
void print_preorder() const
void print_tree() const
Node< T > * get_root() const
void dot_helper(const Node< T > *node, std::ostream &out, int &null_count) const
void inorder(const Node< T > *node) const
void print_tree_helper(const Node< T > *node, const std::string &prefix, bool is_left) const
Node< T > * p_head
Definition cppx.h:102
void preorder(const Node< T > *node) const
void print_inorder() const
bool is_empty() const
void levelorder(const Node< T > *node) const
BinaryTree & operator=(const BinaryTree &other)
void dump_to_dot(const std::string &filename) const
void print_postorder() const
void set_root(Node< T > *root)
Node< T > * make_node(const T &val)
Definition cppx.h:17