Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
avl.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
38#include <algorithm>
39#include <random>
40#include <set>
41#include <vector>
42
43#include <gtest/gtest.h>
44
45#include <tpl_avl.H>
46
47using namespace Aleph;
48using namespace testing;
49
50namespace
51{
52 template <class Tree>
53 struct NodePool
54 {
55 using Node = typename Tree::Node;
56
57 std::vector<Node *> allocated;
58
59 Node * make(const typename Node::key_type & key)
60 {
61 Node * p = new Node(key);
62 allocated.push_back(p);
63 return p;
64 }
65
66 void forget(Node * p) noexcept
67 {
68 for (auto & q : allocated)
69 if (q == p)
70 {
71 q = nullptr;
72 return;
73 }
74 }
75
76 ~NodePool()
77 {
78 for (Node * p : allocated)
79 delete p;
80 }
81 };
82
83 template <class Node>
84 std::vector<typename Node::key_type> inorder_keys(Node * root)
85 {
86 std::vector<typename Node::key_type> keys;
87 Aleph::infix_for_each<Node>(root, [&] (Node * p) { keys.push_back(KEY(p)); });
88 return keys;
89 }
90}
91
93{
96
97 const std::vector<int> input{5, 3, 7, 2, 4, 6, 8};
98 for (int k : input)
99 ASSERT_NE(t.insert(pool.make(k)), nullptr);
100
101 EXPECT_TRUE(t.verify());
103
104 auto * found = t.search(4);
105 ASSERT_NE(found, nullptr);
106 EXPECT_EQ(KEY(found), 4);
107
108 std::vector<int> it_keys;
109 for (Avl_Tree<int>::Iterator it(t); it.has_curr(); it.next_ne())
110 it_keys.push_back(KEY(it.get_curr_ne()));
111
112 std::vector<int> expected = input;
113 std::sort(expected.begin(), expected.end());
115}
116
118{
121
122 auto * a = pool.make(5);
123 auto * b = pool.make(5);
124
125 ASSERT_NE(t.insert(a), nullptr);
126 EXPECT_EQ(t.insert(b), nullptr);
127
128 auto * c = pool.make(5);
129 auto * got = t.search_or_insert(c);
130 ASSERT_NE(got, nullptr);
131 EXPECT_NE(got, c);
132 EXPECT_EQ(KEY(got), 5);
133
134 EXPECT_TRUE(t.verify());
135}
136
137// Tests for optimistic search edge cases
139{
140 /*
141 * Build tree: 50
142 * / \
143 * 25 75
144 * / \
145 * 10 30
146 */
147 // Then try to insert duplicate of 25 (intermediate level)
150
151 ASSERT_NE(t.insert(pool.make(50)), nullptr);
152 ASSERT_NE(t.insert(pool.make(25)), nullptr);
153 ASSERT_NE(t.insert(pool.make(75)), nullptr);
154 ASSERT_NE(t.insert(pool.make(10)), nullptr);
155 ASSERT_NE(t.insert(pool.make(30)), nullptr);
156
157 // Try duplicate at intermediate level
158 EXPECT_EQ(t.insert(pool.make(25)), nullptr);
159 EXPECT_TRUE(t.verify());
160
161 // search_or_insert should return existing node
162 auto * dup = pool.make(25);
163 auto * found = t.search_or_insert(dup);
164 EXPECT_NE(found, dup);
165 EXPECT_EQ(KEY(found), 25);
166 EXPECT_TRUE(t.verify());
167
168 // Remove the intermediate node should work
169 auto * removed = t.remove(25);
170 ASSERT_NE(removed, nullptr);
171 EXPECT_EQ(KEY(removed), 25);
172 EXPECT_TRUE(t.verify());
173}
174
176{
177 // Build tree where duplicate search goes only left
178 // Tree: 100
179 // /
180 // 50
181 // /
182 // 25
183 // Search for 25 (only left descents, candidate should be nullptr until found)
186
187 ASSERT_NE(t.insert(pool.make(100)), nullptr);
188 ASSERT_NE(t.insert(pool.make(50)), nullptr);
189 ASSERT_NE(t.insert(pool.make(25)), nullptr);
190
191 // Insert key smaller than all - should work (no duplicate)
192 ASSERT_NE(t.insert(pool.make(10)), nullptr);
193 EXPECT_TRUE(t.verify());
194
195 // Try duplicate of leftmost
196 EXPECT_EQ(t.insert(pool.make(25)), nullptr);
197 EXPECT_TRUE(t.verify());
198}
199
201{
202 // Build a deeper tree and test duplicate at various levels
205
206 // Insert in order that creates a balanced tree
207 for (int k : {50, 25, 75, 12, 37, 62, 87, 6, 18, 31, 43})
208 ASSERT_NE(t.insert(pool.make(k)), nullptr);
209
210 EXPECT_TRUE(t.verify());
211
212 // Test duplicates at different levels
213 EXPECT_EQ(t.insert(pool.make(50)), nullptr); // root
214 EXPECT_EQ(t.insert(pool.make(25)), nullptr); // level 1
215 EXPECT_EQ(t.insert(pool.make(37)), nullptr); // level 2
216 EXPECT_EQ(t.insert(pool.make(31)), nullptr); // level 3
217
218 EXPECT_TRUE(t.verify());
219
220 // Remove and verify tree integrity
221 for (int k : {31, 37, 25, 50})
222 {
223 auto * rem = t.remove(k);
224 ASSERT_NE(rem, nullptr);
225 EXPECT_EQ(KEY(rem), k);
226 EXPECT_TRUE(t.verify());
227 }
228}
229
231{
234
235 ASSERT_NE(t.insert_dup(pool.make(5)), nullptr);
236 ASSERT_NE(t.insert_dup(pool.make(5)), nullptr);
237 ASSERT_NE(t.insert_dup(pool.make(5)), nullptr);
238
239 EXPECT_TRUE(t.verify());
240 EXPECT_EQ(inorder_keys<Avl_Tree<int>::Node>(t.getRoot()), (std::vector<int>{5, 5, 5}));
241}
242
244{
247 for (int k : {1, 2, 3})
248 ASSERT_NE(t.insert(pool.make(k)), nullptr);
249
250 EXPECT_EQ(t.remove(42), nullptr);
251 EXPECT_TRUE(t.verify());
252}
253
255{
258 for (int k : {3, 1, 4, 2})
259 ASSERT_NE(t.insert(pool.make(k)), nullptr);
260
261 auto * removed = t.remove(1);
262 ASSERT_NE(removed, nullptr);
263 EXPECT_EQ(KEY(removed), 1);
266 EXPECT_EQ(static_cast<int>(DIFF(removed)), 0);
267
268 EXPECT_TRUE(t.verify());
269
270 pool.forget(removed);
271 delete removed;
272}
273
275{
278
279 std::mt19937 rng(12345);
280 std::uniform_int_distribution<int> dist(0, 500);
281
282 std::set<int> present;
283
284 for (int i = 0; i < 300; ++i)
285 {
286 int k = dist(rng);
287 auto * p = pool.make(k);
288 auto * ins = t.insert(p);
289 if (ins == nullptr)
290 {
291 pool.forget(p);
292 delete p;
293 }
294 else
295 present.insert(k);
296
297 ASSERT_TRUE(t.verify());
298 }
299
300 for (int i = 0; i < 200; ++i)
301 {
302 int k = dist(rng);
303 auto * removed = t.remove(k);
304 if (removed != nullptr)
305 {
306 present.erase(k);
307 pool.forget(removed);
308 delete removed;
309 }
310 ASSERT_TRUE(t.verify());
311 }
312}
313
315{
316 {
319 ASSERT_NE(t.insert(pool.make(3)), nullptr);
320 ASSERT_NE(t.insert(pool.make(2)), nullptr);
321 ASSERT_NE(t.insert(pool.make(1)), nullptr); // LL
322 ASSERT_TRUE(t.verify());
323 EXPECT_EQ(inorder_keys<Avl_Tree<int>::Node>(t.getRoot()), (std::vector<int>{1, 2, 3}));
324 }
325
326 {
329 ASSERT_NE(t.insert(pool.make(1)), nullptr);
330 ASSERT_NE(t.insert(pool.make(2)), nullptr);
331 ASSERT_NE(t.insert(pool.make(3)), nullptr); // RR
332 ASSERT_TRUE(t.verify());
333 EXPECT_EQ(inorder_keys<Avl_Tree<int>::Node>(t.getRoot()), (std::vector<int>{1, 2, 3}));
334 }
335
336 {
339 ASSERT_NE(t.insert(pool.make(3)), nullptr);
340 ASSERT_NE(t.insert(pool.make(1)), nullptr);
341 ASSERT_NE(t.insert(pool.make(2)), nullptr); // LR
342 ASSERT_TRUE(t.verify());
343 EXPECT_EQ(inorder_keys<Avl_Tree<int>::Node>(t.getRoot()), (std::vector<int>{1, 2, 3}));
344 }
345
346 {
349 ASSERT_NE(t.insert(pool.make(1)), nullptr);
350 ASSERT_NE(t.insert(pool.make(3)), nullptr);
351 ASSERT_NE(t.insert(pool.make(2)), nullptr); // RL
352 ASSERT_TRUE(t.verify());
353 EXPECT_EQ(inorder_keys<Avl_Tree<int>::Node>(t.getRoot()), (std::vector<int>{1, 2, 3}));
354 }
355}
356
358{
361
362 std::mt19937 rng(123456);
363 std::uniform_int_distribution<int> dist(0, 2000);
364 std::bernoulli_distribution do_insert(0.6);
365
366 std::set<int> oracle;
367
368 for (int i = 0; i < 1500; ++i)
369 {
370 int k = dist(rng);
371 if (do_insert(rng))
372 {
373 auto * p = pool.make(k);
374 auto * ins = t.insert(p);
375 if (ins == nullptr)
376 {
377 pool.forget(p);
378 delete p;
379 }
380 else
381 oracle.insert(k);
382 }
383 else
384 {
385 if (auto * removed = t.remove(k); removed != nullptr)
386 {
387 oracle.erase(k);
388 pool.forget(removed);
389 delete removed;
390 }
391 }
392
393 ASSERT_TRUE(t.verify());
394
395 std::vector<int> expected(oracle.begin(), oracle.end());
398 }
399}
400
402{
403 struct Greater
404 {
405 bool operator()(int a, int b) const noexcept { return a > b; }
406 };
407
410
411 for (int k : {1, 2, 3, 4, 5})
412 ASSERT_NE(t.insert(pool.make(k)), nullptr);
413
414 EXPECT_TRUE(t.verify());
416 const std::vector<int> expected{5, 4, 3, 2, 1};
418
419 auto * removed = t.remove(4);
420 ASSERT_NE(removed, nullptr);
421 pool.forget(removed);
422 delete removed;
423
424 EXPECT_TRUE(t.verify());
425}
426
427// Tests the candidate_pos == avl_stack.size() branch (zero-pop path).
428// This occurs when the duplicate key is the current maximum: the last
429// descend is always to the right so candidate_pos equals the stack size
430// at the end of the loop, making to_pop == 0 and popn() is never called.
432{
435
436 // Tree: 10 -> 20 -> 30 (right-spine). 30 is the current maximum.
437 ASSERT_NE(t.insert(pool.make(10)), nullptr);
438 ASSERT_NE(t.insert(pool.make(20)), nullptr);
439 ASSERT_NE(t.insert(pool.make(30)), nullptr);
440 ASSERT_TRUE(t.verify());
441
442 // Duplicate of maximum: search goes 10->20->30->NullPtr,
443 // candidate_pos == avl_stack.size() at end, so to_pop == 0.
444 EXPECT_EQ(t.insert(pool.make(30)), nullptr);
445 EXPECT_TRUE(t.verify());
446
447 // search_or_insert must also find the existing node without corruption.
448 auto * dup = pool.make(30);
449 auto * found = t.search_or_insert(dup);
450 EXPECT_NE(found, dup);
451 EXPECT_EQ(KEY(found), 30);
452 EXPECT_TRUE(t.verify());
453}
454
455// Randomised variant: repeatedly insert many sequences that include a
456// duplicate of the current maximum to stress the zero-pop branch.
458{
459 std::mt19937 rng(77777);
460 std::uniform_int_distribution<int> n_dist(1, 50);
461
462 for (int trial = 0; trial < 200; ++trial)
463 {
466
467 int n = n_dist(rng);
468 int max_key = 0;
469 for (int i = 1; i <= n; ++i)
470 {
471 ASSERT_NE(t.insert(pool.make(i)), nullptr);
472 max_key = i;
473 }
474
475 // Insert a duplicate of the current maximum
476 EXPECT_EQ(t.insert(pool.make(max_key)), nullptr);
477 ASSERT_TRUE(t.verify()) << "Invariant violated after duplicate-max on trial " << trial;
478 }
479}
480
481// ============================================================================
482// STRESS TESTS / FUZZING
483// ============================================================================
484
485// Stress test: ascending insertion (worst case for naive BST)
487{
490
491 const int n = 10000;
492
493 for (int i = 0; i < n; ++i)
494 {
495 ASSERT_NE(t.insert(pool.make(i)), nullptr) << "Insert failed at i=" << i;
496 ASSERT_TRUE(t.verify()) << "AVL invariant violated at i=" << i;
497 }
498
499 // Verify all elements are present
500 for (int i = 0; i < n; ++i)
501 ASSERT_NE(t.search(i), nullptr) << "Element " << i << " not found";
502}
503
504// Stress test: descending insertion
506{
509
510 const int n = 10000;
511
512 for (int i = n - 1; i >= 0; --i)
513 {
514 ASSERT_NE(t.insert(pool.make(i)), nullptr);
515 ASSERT_TRUE(t.verify());
516 }
517
518 for (int i = 0; i < n; ++i)
519 ASSERT_NE(t.search(i), nullptr);
520}
521
522// Stress test: zigzag insertion pattern
524{
527
528 const int n = 5000;
529
530 // Insert in zigzag pattern: 0, n-1, 1, n-2, 2, n-3, ...
531 for (int i = 0; i < n / 2; ++i)
532 {
533 ASSERT_NE(t.insert(pool.make(i)), nullptr);
534 ASSERT_TRUE(t.verify());
535 ASSERT_NE(t.insert(pool.make(n - 1 - i)), nullptr);
536 ASSERT_TRUE(t.verify());
537 }
538
539 for (int i = 0; i < n; ++i)
540 ASSERT_NE(t.search(i), nullptr);
541}
542
543// Stress test: large scale fuzzing with oracle
545{
548
549 std::mt19937 rng(99999);
550 std::uniform_int_distribution<int> key_dist(0, 50000);
551 std::uniform_int_distribution<int> op_dist(0, 2);
552
553 std::set<int> oracle;
554
555 const int num_ops = 20000;
556
557 for (int i = 0; i < num_ops; ++i)
558 {
559 int key = key_dist(rng);
560 int op = op_dist(rng);
561
562 switch (op)
563 {
564 case 0: // Insert
565 {
566 auto * p = pool.make(key);
567 auto * ins = t.insert(p);
568 if (ins == nullptr)
569 {
570 pool.forget(p);
571 delete p;
572 EXPECT_TRUE(oracle.count(key) > 0);
573 }
574 else
575 {
576 EXPECT_TRUE(oracle.count(key) == 0);
577 oracle.insert(key);
578 }
579 break;
580 }
581 case 1: // Remove
582 {
583 auto * removed = t.remove(key);
584 if (removed != nullptr)
585 {
586 EXPECT_TRUE(oracle.count(key) > 0);
587 oracle.erase(key);
588 pool.forget(removed);
589 delete removed;
590 }
591 else
592 {
593 EXPECT_TRUE(oracle.count(key) == 0);
594 }
595 break;
596 }
597 case 2: // Search
598 {
599 auto * found = t.search(key);
600 bool in_oracle = oracle.count(key) > 0;
601 EXPECT_EQ(found != nullptr, in_oracle);
602 if (found)
603 EXPECT_EQ(KEY(found), key);
604 break;
605 }
606 }
607
608 ASSERT_TRUE(t.verify()) << "AVL invariant violated at op " << i;
609 }
610
611 // Final verification
612 std::vector<int> expected(oracle.begin(), oracle.end());
615}
616
617// Stress test: bulk insert then bulk remove
619{
622
623 const int n = 10000;
624
625 // Bulk insert
626 std::vector<int> keys(n);
627 std::iota(keys.begin(), keys.end(), 0);
628
629 std::mt19937 rng(12345);
630 std::shuffle(keys.begin(), keys.end(), rng);
631
632 for (int k : keys)
633 {
634 ASSERT_NE(t.insert(pool.make(k)), nullptr);
635 }
636
637 ASSERT_TRUE(t.verify());
638
639 // Bulk remove in different random order
640 std::shuffle(keys.begin(), keys.end(), rng);
641
642 for (int k : keys)
643 {
644 auto * removed = t.remove(k);
645 ASSERT_NE(removed, nullptr) << "Remove failed for key " << k;
646 pool.forget(removed);
647 delete removed;
648 ASSERT_TRUE(t.verify());
649 }
650
652}
653
654// Stress test: repeated insert_dup (duplicates allowed)
656{
659
660 const int num_keys = 100;
661 const int dups_per_key = 50;
662
663 // Insert many duplicates of each key
664 for (int k = 0; k < num_keys; ++k)
665 {
666 for (int d = 0; d < dups_per_key; ++d)
667 {
668 ASSERT_NE(t.insert_dup(pool.make(k)), nullptr);
669 }
670 }
671
672 ASSERT_TRUE(t.verify());
673
674 // Verify inorder traversal has correct count
677
678 // Verify sorted
679 EXPECT_TRUE(std::is_sorted(keys.begin(), keys.end()));
680}
681
682// Stress test: alternating insert and remove
684{
687
688 std::set<int> present;
689 std::mt19937 rng(54321);
690 std::uniform_int_distribution<int> dist(0, 10000);
691
692 const int n = 15000;
693
694 for (int i = 0; i < n; ++i)
695 {
696 int k = dist(rng);
697
698 if (i % 2 == 0) // Insert
699 {
700 auto * p = pool.make(k);
701 if (t.insert(p) == nullptr)
702 {
703 pool.forget(p);
704 delete p;
705 }
706 else
707 {
708 present.insert(k);
709 }
710 }
711 else // Remove
712 {
713 if (auto * removed = t.remove(k); removed)
714 {
715 present.erase(k);
716 pool.forget(removed);
717 delete removed;
718 }
719 }
720
721 ASSERT_TRUE(t.verify()) << "AVL invariant violated at i=" << i;
722 }
723
724 // Final check
725 std::vector<int> expected(present.begin(), present.end());
727}
728
729// Stress test with string keys
731{
734
735 std::mt19937 rng(11111);
736 std::uniform_int_distribution<int> len_dist(1, 30);
737 std::uniform_int_distribution<int> char_dist('a', 'z');
738
739 auto random_string = [&]() {
740 int len = len_dist(rng);
741 std::string s;
742 s.reserve(len);
743 for (int i = 0; i < len; ++i)
744 s += static_cast<char>(char_dist(rng));
745 return s;
746 };
747
748 std::set<std::string> oracle;
749
750 const int n = 5000;
751
752 for (int i = 0; i < n; ++i)
753 {
754 std::string s = random_string();
755 auto * p = pool.make(s);
756 if (t.insert(p) != nullptr)
757 oracle.insert(s);
758 else
759 {
760 pool.forget(p);
761 delete p;
762 }
763 }
764
765 ASSERT_TRUE(t.verify());
766
767 // Verify all oracle strings are present
768 for (const auto & s : oracle)
769 ASSERT_NE(t.search(s), nullptr) << "String key missing: " << s;
770}
static string random_string(std::mt19937 &rng, size_t len)
bool is_avl(Node *p)
Validate that a tree satisfies AVL properties.
Definition avlNode.H:123
#define DIFF(p)
Access the balance factor of node p.
Definition avlNode.H:95
WeightedDigraph::Node Node
@ KEY
Definition btreepic.C:169
Node * search(const Key &key) const noexcept
Search a node containing key; if found, then a pointer to the node containing it is returned; otherwi...
Definition tpl_avl.H:533
Node * search_or_insert(Node *p) noexcept
Search or insert a key.
Definition tpl_avl.H:598
Node * insert_dup(Node *p) noexcept
Insert the node p without testing for key duplicity.
Definition tpl_avl.H:621
constexpr Node *& getRoot() noexcept
Return a modifiable reference to tree's root.
Definition tpl_avl.H:526
Node * insert(Node *p) noexcept
Insert the node pointed by p in the tree.
Definition tpl_avl.H:561
bool verify() const noexcept
Definition tpl_avl.H:694
Node * remove(const Key &key) noexcept
Remove from an AVL tree the node containing key key.
Definition tpl_avl.H:640
void forget(Node *p)
Definition rand-tree.cc:93
Node * make(int key)
Definition rand-tree.cc:86
QuadNode Node
Definition quadtree.H:128
#define TEST(name)
static mt19937 rng
__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:4060
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
std::vector< int > inorder_keys(NodeT *root)
Definition rand-tree.cc:59
AVL binary search tree with nodes without virtual destructor.
Definition tpl_avl.H:737
#define RLINK(i, n)
int keys[]
#define LLINK(i, n)
ValueArg< size_t > num_keys
Definition testHash.C:45
static int * k
AVL tree implementation (height-balanced BST).