Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tree-node.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
33
38# include <gtest/gtest.h>
39
40# include <tpl_binNode.H>
41# include <tpl_tree_node.H>
42# include <ah-zip.H>
43# include <ah-string-utils.H>
44
45# include "tree-node-common.H"
46
47using namespace std;
48using namespace Aleph;
49
51{
53
60
61 ASSERT_EQ(p.get_right_child(), nullptr);
62 ASSERT_EQ(p.get_left_child(), nullptr);
63
64 ASSERT_EQ(p.get_child(0), nullptr);
65 ASSERT_EQ(p.get_parent(), nullptr);
66
67 ASSERT_EQ(p.get_left_tree(), nullptr);
68 ASSERT_EQ(p.get_right_tree(), nullptr);
69
70 ASSERT_TRUE(p.children().is_empty());
71
72 ASSERT_TRUE(p.traverse([] (auto) { return true; }));
73 ASSERT_FALSE(p.traverse([] (auto) { return false; }));
74
77 ASSERT_EQ(it.get_curr(), &p);
80 ASSERT_THROW(it.get_curr(), overflow_error);
81 ASSERT_THROW(it.next(), overflow_error);
82 it.reset_first();
84 ASSERT_EQ(it.get_curr(), &p);
87 ASSERT_THROW(it.get_curr(), overflow_error);
88 ASSERT_THROW(it.next(), overflow_error);
89
91 ASSERT_FALSE(cit.has_curr());
92 ASSERT_THROW(cit.get_curr(), overflow_error);
93 ASSERT_THROW(cit.next(), overflow_error);
94}
95
97{
99 Tree_Node<int> left(1);
100 Tree_Node<int> right(2);
104
105 root.insert_rightmost_child(&left);
106 root.insert_rightmost_child(&right);
109 left_left.insert_rightmost_child(&deep);
110
111 ASSERT_EQ(root.get_parent(), nullptr);
112 ASSERT_EQ(left.get_parent(), &root);
113 ASSERT_EQ(right.get_parent(), &root);
114 ASSERT_EQ(left_left.get_parent(), &left);
115 ASSERT_EQ(left_right.get_parent(), &left);
116 ASSERT_EQ(deep.get_parent(), &left_left);
117}
118
120{
126
127 root.insert_rightmost_child(&old_left);
128 root.insert_rightmost_child(&old_right);
129 old_left.insert_rightmost_child(&old_left_child);
130
131 root.insert_leftmost_child(&new_left);
132
133 ASSERT_EQ(root.get_left_child(), &new_left);
134 ASSERT_EQ(root.get_child(0), &new_left);
135 ASSERT_EQ(root.get_child(1), &old_left);
136 ASSERT_EQ(root.get_child(2), &old_right);
137
138 ASSERT_EQ(new_left.get_parent(), &root);
139 ASSERT_EQ(old_left.get_parent(), &root);
140 ASSERT_EQ(old_right.get_parent(), &root);
141 ASSERT_EQ(old_left_child.get_parent(), &old_left);
142
143 ASSERT_TRUE(new_left.is_leftmost());
144 ASSERT_FALSE(new_left.is_rightmost());
145 ASSERT_FALSE(old_left.is_leftmost());
146 ASSERT_FALSE(old_right.is_leftmost());
147 ASSERT_TRUE(old_right.is_rightmost());
148}
149
151{
154 Tree_Node<int> right(2);
157
158 root.insert_rightmost_child(&old_left);
159 root.insert_rightmost_child(&right);
160 old_left.insert_rightmost_child(&old_left_child);
161
162 old_left.insert_left_sibling(&new_left);
163
164 ASSERT_EQ(root.get_left_child(), &new_left);
165 ASSERT_EQ(root.get_child(0), &new_left);
166 ASSERT_EQ(root.get_child(1), &old_left);
167 ASSERT_EQ(root.get_child(2), &right);
168
169 ASSERT_EQ(new_left.get_parent(), &root);
170 ASSERT_EQ(old_left.get_parent(), &root);
171 ASSERT_EQ(right.get_parent(), &root);
172 ASSERT_EQ(old_left_child.get_parent(), &old_left);
173
174 ASSERT_TRUE(new_left.is_leftmost());
175 ASSERT_FALSE(new_left.is_rightmost());
176 ASSERT_FALSE(old_left.is_leftmost());
177 ASSERT_FALSE(right.is_leftmost());
178 ASSERT_TRUE(right.is_rightmost());
179}
180
182{
183 BinNode<int> n1(1);
184 BinNode<int> n2(2);
185 BinNode<int> n3(3);
186
187 RLINK(&n1) = &n2;
188 RLINK(&n2) = &n3;
189
191 ASSERT_NE(forest, nullptr);
192
193 size_t count = 0;
194 for (auto * t = forest; t != nullptr; t = t->get_right_sibling(), ++count)
195 {
196 EXPECT_TRUE(t->is_root()) << "tree key " << t->get_key()
197 << " must remain a forest root";
198 EXPECT_EQ(t->get_parent(), nullptr);
199 }
200
201 EXPECT_EQ(count, 3);
203}
204
206{
210
211 tree1.insert_right_sibling(&tree2);
212 tree2.insert_right_sibling(&tree3);
213
214 ASSERT_EQ(tree1.get_right_tree(), &tree2);
215 ASSERT_EQ(tree2.get_right_tree(), &tree3);
216 ASSERT_EQ(tree3.get_right_tree(), nullptr);
217
218 ASSERT_TRUE(tree1.is_root());
219 ASSERT_TRUE(tree2.is_root());
220 ASSERT_TRUE(tree3.is_root());
221
222 ASSERT_EQ(tree1.get_parent(), nullptr);
223 ASSERT_EQ(tree2.get_parent(), nullptr);
224 ASSERT_EQ(tree3.get_parent(), nullptr);
225}
226
248
250{
252 Tree_Node<int>* child1 = new Tree_Node<int>(2);
253 Tree_Node<int>* child2 = new Tree_Node<int>(3);
254
255 root->insert_rightmost_child(child1);
256 root->insert_rightmost_child(child2);
257
258 // Layout: child1 -> child2 (rightmost)
259 // Destroying a non-leftmost sibling with a left sibling
260 destroy_tree(child2);
261
262 ASSERT_EQ(root->get_left_child(), child1);
263 ASSERT_EQ(root->get_right_child(), child1);
265 ASSERT_TRUE(child1->is_rightmost());
266 ASSERT_EQ(child1->get_right_sibling(), nullptr);
267
269}
270
272{
273 // Regression: destroy_tree() unlinked a node from its sibling list
274 // without restoring is_rightmost()/is_leftmost() on the neighbor taking
275 // its place. get_right_child()/get_left_child() use the raw (flag-blind)
276 // Dlink links and so cannot detect this; get_right_sibling() and anything
277 // built on it (for_each_child(), Children_Iterator) are flag-gated and
278 // did loop forever on the surviving sibling before this fix.
279 auto *root = new Tree_Node<int>(0);
280 auto *a = new Tree_Node<int>(1);
281 auto *b = new Tree_Node<int>(2);
282 auto *c = new Tree_Node<int>(3);
283 root->insert_rightmost_child(a);
284 root->insert_rightmost_child(b);
285 root->insert_rightmost_child(c); // root -> a, b, c (c is rightmost)
286
287 destroy_tree(c);
288
289 EXPECT_TRUE(b->is_rightmost());
290 EXPECT_EQ(b->get_right_sibling(), nullptr);
291
292 int count = 0;
293 root->for_each_child([&count](auto) { ++count; });
294 EXPECT_EQ(count, 2); // a, b -- would loop forever before the fix
295
297}
298
300{
301 // Symmetric case: destroying the current leftmost child must promote
302 // its former right neighbor to is_leftmost().
303 auto *root = new Tree_Node<int>(0);
304 auto *a = new Tree_Node<int>(1);
305 auto *b = new Tree_Node<int>(2);
306 auto *c = new Tree_Node<int>(3);
307 root->insert_rightmost_child(a);
308 root->insert_rightmost_child(b);
309 root->insert_rightmost_child(c); // root -> a (leftmost), b, c
310
311 destroy_tree(a);
312
313 EXPECT_TRUE(b->is_leftmost());
314 EXPECT_EQ(b->get_left_sibling(), nullptr);
315 EXPECT_EQ(root->get_left_child(), b);
316
317 int count = 0;
318 root->for_each_child([&count](auto) { ++count; });
319 EXPECT_EQ(count, 2); // b, c
320
322}
323
325{
326 Tree_Node<int> p1 = 1;
327 Tree_Node<int> p2 = 2;
328 Tree_Node<int> p3 = 3;
329 Tree_Node<int> p4 = 4;
330 Tree_Node<int> p5 = 5;
331
332 /* 1 insert_leftmost_child() test
333 |
334 2
335 */
336 p1.insert_leftmost_child(&p2);
337 ASSERT_TRUE(p1.is_root());
340 ASSERT_FALSE(p1.is_leaf());
341 ASSERT_FALSE(p2.is_root());
344
345 /* 1 insert_rightmost_child() test
346 /\
347 2 3
348 */
350 ASSERT_TRUE(p1.is_root());
353 ASSERT_FALSE(p1.is_leaf());
354 ASSERT_TRUE(p2.is_leaf());
355 ASSERT_FALSE(p2.is_root());
358 ASSERT_TRUE(p2.is_leaf());
359 ASSERT_FALSE(p3.is_root());
362
363 /* 0
364 / | \
365 2 3 5
366 */
368 ASSERT_TRUE(p1.is_root());
371 ASSERT_FALSE(p1.is_leaf());
372 ASSERT_FALSE(p2.is_root());
375 ASSERT_TRUE(p2.is_leaf());
376 ASSERT_FALSE(p3.is_root());
379 ASSERT_TRUE(p3.is_leaf());
380 ASSERT_FALSE(p5.is_leftmost());
381 ASSERT_TRUE(p5.is_rightmost());
382 ASSERT_FALSE(p5.is_root());
383 ASSERT_TRUE(p5.is_leaf());
384
385 /* 1
386 / / | |
387 2 3 4 5
388 */
389 p5.insert_left_sibling(&p4);
390 ASSERT_TRUE(p1.is_root());
393 ASSERT_FALSE(p1.is_leaf());
394 ASSERT_FALSE(p2.is_root());
397 ASSERT_TRUE(p2.is_leaf());
398
399 ASSERT_FALSE(p3.is_root());
402 ASSERT_TRUE(p3.is_leaf());
403
404 ASSERT_FALSE(p4.is_root());
407 ASSERT_TRUE(p4.is_leaf());
408
409 ASSERT_FALSE(p5.is_leftmost());
410 ASSERT_TRUE(p5.is_rightmost());
411 ASSERT_FALSE(p5.is_root());
412 ASSERT_TRUE(p5.is_leaf());
413
414 ASSERT_EQ(p1.get_left_child(), &p2);
416
417 ASSERT_EQ(p2.get_left_sibling(), nullptr);
418 ASSERT_EQ(p2.get_right_sibling(), &p3);
419
420 ASSERT_EQ(p3.get_left_sibling(), &p2);
421 ASSERT_EQ(p3.get_right_sibling(), &p4);
422
423 ASSERT_EQ(p4.get_left_sibling(), &p3);
425
426 ASSERT_EQ(p5.get_left_sibling(), &p4);
427 ASSERT_EQ(p5.get_right_sibling(), nullptr);
428
429 ASSERT_EQ(p1.get_child(0), &p2);
430 ASSERT_EQ(p1.get_child(1), &p3);
431 ASSERT_EQ(p1.get_child(2), &p4);
432 ASSERT_EQ(p1.get_child(3), &p5);
433
434 int k = 0;
435 ASSERT_TRUE(p1.traverse([&k] (auto p) { return p->get_key() == ++k; }));
436 ASSERT_EQ(k, 5);
437 k = 1;
438 ASSERT_TRUE(p1.children_nodes().traverse([&k] (auto p)
439 { return p->get_key() == ++k; }));
440 ASSERT_EQ(k, 5);
441 k = 1;
442 ASSERT_TRUE(p1.children().traverse([&k] (auto i) { return i == ++k; }));
443 ASSERT_EQ(k, 5);
444}
445
447{
448 {
449 Tree_Node<int>::Iterator it = nullptr;
451 ASSERT_THROW(it.get_curr(), overflow_error);
452 ASSERT_THROW(it.next(), overflow_error);
453 }
454
455 {
456 Tree_Node<int> p(0);
457 auto it = p.get_it();
458 ASSERT_TRUE(it.has_curr());
459 ASSERT_EQ(it.get_pos(), 0);
460 ASSERT_NO_THROW(it.next());
461 ASSERT_FALSE(it.has_curr());
462 ASSERT_EQ(it.get_pos(), 1);
463 ASSERT_THROW(it.get_curr(), overflow_error);
464 ASSERT_THROW(it.next(), overflow_error);
465 }
466
467 {
468 Tree_Node<int> p0(0);
469 Tree_Node<int> p1(1);
470 p0.insert_leftmost_child(&p1);
471 auto it = p0.get_it();
472 ASSERT_TRUE(it.has_curr());
473 ASSERT_EQ(it.get_curr(), &p0);
474 ASSERT_NO_THROW(it.next());
475 ASSERT_TRUE(it.has_curr());
476 ASSERT_EQ(it.get_curr(), &p1);
477 ASSERT_NO_THROW(it.next());
478 ASSERT_FALSE(it.has_curr());
479 ASSERT_THROW(it.get_curr(), overflow_error);
480 ASSERT_THROW(it.next(), overflow_error);
481
482 ASSERT_NO_THROW(it.reset_first());
483 ASSERT_TRUE(it.has_curr());
484 ASSERT_EQ(it.get_curr(), &p0);
485 ASSERT_NO_THROW(it.next());
486 ASSERT_TRUE(it.has_curr());
487 ASSERT_EQ(it.get_curr(), &p1);
488 ASSERT_NO_THROW(it.next());
489 ASSERT_FALSE(it.has_curr());
490 ASSERT_THROW(it.get_curr(), overflow_error);
491 ASSERT_THROW(it.next(), overflow_error);
492 }
493}
494
496{
497 auto itl = l.get_it();
498 size_t k = 0;
499 for (auto it = root->get_it(); it.has_curr(); it.next(), itl.next(), ++k)
500 ASSERT_EQ(it.get_curr()->get_key(), itl.get_curr());
501 ASSERT_GT(k, 0);
502}
503
505{
506 {
507 Tree_Node<int> * root = nullptr;
508 ASSERT_EQ(clone_tree(root), nullptr);
509 }
510 {
512 auto rootp = clone_tree(&root);
513 ASSERT_NE(rootp, nullptr);
514 ASSERT_EQ(root.get_key(), rootp->get_key());
516 }
517}
518
520{
521 int i = 0;
522 ASSERT_TRUE(root->level_traverse([&i] (auto p)
523 {
524 return p->get_key() == i++;
525 }));
526 ASSERT_EQ(i, 31);
527}
528
530{
531 Tree_Node<int> * clone = clone_tree(root);
533 using Pit = Pair_Iterator<It>;
534 for (Pit it{It(root), It(clone)}; it.has_curr(); it.next())
535 {
536 auto p = it.get_curr();
537 ASSERT_EQ(p.first->get_key(), p.second->get_key());
538 }
539 destroy_tree(clone);
540}
541
543{
544 {
545 Tree_Node<int> * root = nullptr;
546 ASSERT_EQ(root, nullptr);
547 }
548 {
550 size_t k = 0;
551 ASSERT_TRUE(root.traverse([&k] (auto p) { k++; return p->get_key() == 5; }));
552 ASSERT_EQ(k, 1);
553 }
554}
555
557{
559
560 auto * t1 = new Node("root");
561 t1->insert_rightmost_child(new Node("A"));
562 t1->insert_rightmost_child(new Node("B"));
563
564 auto * t2 = new Node("ROOT");
565 t2->insert_rightmost_child(new Node("a"));
566 t2->insert_rightmost_child(new Node("b"));
567
568 auto nocase = [] (const std::string & a, const std::string & b)
569 {
570 if (a.size() != b.size())
571 return false;
572 for (size_t i = 0; i < a.size(); ++i)
573 if (std::tolower(static_cast<unsigned char>(a[i])) !=
574 std::tolower(static_cast<unsigned char>(b[i])))
575 return false;
576 return true;
577 };
578
579 ASSERT_TRUE((are_tree_equal<Node, decltype(nocase)>(t1, t2, nocase)));
580
583}
584
586{
587 auto it = l.get_it();
588 size_t k = 0;
589 auto ret = root->traverse([&it, &k] (auto p)
590 {
591 bool r = p->get_key() == it.get_curr();
592 it.next(); ++k;
593 return r;
594 });
596 ASSERT_EQ(k, l.size());
597}
598
600{
601 int d[100];
602 size_t sz;
603 auto p = search_deway(root, 14, d, 100, sz);
604 ASSERT_EQ(p->get_key(), 14);
605 ASSERT_EQ(sz, 3);
606 ASSERT_EQ(d[0], 0);
607 ASSERT_EQ(d[1], 1);
608 ASSERT_EQ(d[2], 3);
609}
610
611/* 0
612
613 1 2 3 4 5
614
6156 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
616
617*/
618
620{
621 auto t1 = clone_tree(root1);
622 auto t2 = clone_tree(root2);
623 auto t3 = clone_tree(root3);
624
625 t1->insert_tree_to_right(t3);
626 t1->insert_tree_to_right(t2);
627
629 DynList<Tree_Node<int>*> flist = t1->trees();
630
631 zip_for_each([] (auto t) { ASSERT_EQ(get<0>(t), get<1>(t)); }, tlist, flist);
632
634}
635
637{
638 auto t = clone_tree(root1);
639 auto t2 = clone_tree(root2);
640
641 t->join(t2);
642
643 DynList<int> l = { 0, 1, 2, 3, 4, 5, 31, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
644 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
645 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43 };
646
647 DynList<int> order;
648 t->level_traverse([&order] (auto p) { order.append(p->get_key()); return true; });
649
650 ASSERT_TRUE(eq(l, order));
651
653}
String manipulation utilities.
Zip iterators and functional operations for multiple containers.
WeightedDigraph::Node Node
Node for binary search tree.
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
Generic filter iterator wrapper.
void next()
Advances the iterator to the next filtered element.
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1065
Iterator that zips two other iterators.
auto get_curr() const
Get current pair (bounds-checked).
Iterator over the children of this.
Preorder iterator over a tree rooted at a Tree_Node.
bool has_curr() const noexcept
Tree_Node * get_curr() const
Forward declaration used by CRTP helpers before the full node definition.
constexpr bool is_leftmost() const noexcept
Returns true if this is the leftmost node among its siblings.
bool traverse(Operation op)
Preorder traversal over all nodes executing op.
Dlink * get_sibling_list() noexcept
Returns the embedded sibling-list link.
Tree_Node * get_left_sibling() const noexcept
Returns the left sibling of this.
constexpr bool is_root() const noexcept
Returns true if this is the root of the general tree.
Tree_Node * get_left_child() const noexcept
Returns the leftmost child of this.
constexpr bool is_rightmost() const noexcept
Returns true if this is the rightmost node among its siblings.
Tree_Node * get_child(const size_t i) const noexcept
Returns the i-th child of this.
void insert_leftmost_child(Tree_Node *p) noexcept
Inserts p as the leftmost child of this.
constexpr bool is_leaf() const noexcept
Returns true if this is a leaf node.
Dlink * get_child_list() noexcept
Returns the embedded child-list link.
Tree_Node * get_right_sibling() const noexcept
Returns the right sibling of this.
Tree_Node * get_left_tree() const noexcept
Returns the tree to the left of this.
void insert_rightmost_child(Tree_Node *p) noexcept
Inserts p as the rightmost child of this.
Tree_Node * get_right_tree() const noexcept
Returns the tree to the right of this.
Tree_Node * get_parent() const noexcept
Returns the parent of this.
Container< Tree_Node * > children_nodes() const
Returns a list with the child nodes of this.
Tree_Node * get_right_child() const noexcept
Returns the rightmost child of this.
void insert_right_sibling(Tree_Node *p) noexcept
Inserts p to the right of this node.
Iterator get_it() const
Container< T > children() const
Returns a list with the contents of the children of this.
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:228
void deway(Tree_Node< int > *p, int prefix[], const int &len, const size_t &dim)
Recursively compute and print Deway numbering for a tree node.
Definition deway.C:118
#define TEST(name)
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
Definition gmpfrxx.h:4071
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
void destroy_tree(Node *root)
Destroys (frees memory) the tree whose root is root.
bool are_tree_equal(Node *t1, Node *t2, Eq &eq)
Returns true if t1 is equal to t2.
void destroy_forest(Node *root)
Destroys (frees memory) the forest whose first tree is root.
Node * search_deway(Node *root, const typename Node::key_type &key, int deway[], const size_t &size, size_t &n)
Searches key in a forest and computes the Dewey number of the node containing the key.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
bool eq(const C1 &c1, const C2 &c2, Eq e=Eq())
Check equality of two containers using a predicate.
void zip_for_each(Op &&op, const Cs &...cs)
Apply op to every zipped tuple.
Definition ah-zip.H:382
bool traverse(Node *root, Op op)
static void clone_tree(Node *src, Node *tgt)
std::ostream & join(const C &c, const std::string &sep, std::ostream &out)
Join elements of an Aleph-style container into a stream.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
STL namespace.
#define RLINK(i, n)
static int * k
gsl_rng * r
Basic binary tree node definitions.
General tree (n-ary tree) node.
#define IS_UNIQUE_SIBLING(p)
DynList< int > l
TEST_F(Simple_Tree, Iterators)
Definition tree-node.cc:495