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
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// ============================================================================
428// STRESS TESTS / FUZZING
429// ============================================================================
430
431// Stress test: ascending insertion (worst case for naive BST)
433{
436
437 const int n = 10000;
438
439 for (int i = 0; i < n; ++i)
440 {
441 ASSERT_NE(t.insert(pool.make(i)), nullptr) << "Insert failed at i=" << i;
442 ASSERT_TRUE(t.verify()) << "AVL invariant violated at i=" << i;
443 }
444
445 // Verify all elements are present
446 for (int i = 0; i < n; ++i)
447 ASSERT_NE(t.search(i), nullptr) << "Element " << i << " not found";
448}
449
450// Stress test: descending insertion
452{
455
456 const int n = 10000;
457
458 for (int i = n - 1; i >= 0; --i)
459 {
460 ASSERT_NE(t.insert(pool.make(i)), nullptr);
461 ASSERT_TRUE(t.verify());
462 }
463
464 for (int i = 0; i < n; ++i)
465 ASSERT_NE(t.search(i), nullptr);
466}
467
468// Stress test: zigzag insertion pattern
470{
473
474 const int n = 5000;
475
476 // Insert in zigzag pattern: 0, n-1, 1, n-2, 2, n-3, ...
477 for (int i = 0; i < n / 2; ++i)
478 {
479 ASSERT_NE(t.insert(pool.make(i)), nullptr);
480 ASSERT_TRUE(t.verify());
481 ASSERT_NE(t.insert(pool.make(n - 1 - i)), nullptr);
482 ASSERT_TRUE(t.verify());
483 }
484
485 for (int i = 0; i < n; ++i)
486 ASSERT_NE(t.search(i), nullptr);
487}
488
489// Stress test: large scale fuzzing with oracle
491{
494
495 std::mt19937 rng(99999);
496 std::uniform_int_distribution<int> key_dist(0, 50000);
497 std::uniform_int_distribution<int> op_dist(0, 2);
498
499 std::set<int> oracle;
500
501 const int num_ops = 20000;
502
503 for (int i = 0; i < num_ops; ++i)
504 {
505 int key = key_dist(rng);
506 int op = op_dist(rng);
507
508 switch (op)
509 {
510 case 0: // Insert
511 {
512 auto * p = pool.make(key);
513 auto * ins = t.insert(p);
514 if (ins == nullptr)
515 {
516 pool.forget(p);
517 delete p;
518 EXPECT_TRUE(oracle.count(key) > 0);
519 }
520 else
521 {
522 EXPECT_TRUE(oracle.count(key) == 0);
523 oracle.insert(key);
524 }
525 break;
526 }
527 case 1: // Remove
528 {
529 auto * removed = t.remove(key);
530 if (removed != nullptr)
531 {
532 EXPECT_TRUE(oracle.count(key) > 0);
533 oracle.erase(key);
534 pool.forget(removed);
535 delete removed;
536 }
537 else
538 {
539 EXPECT_TRUE(oracle.count(key) == 0);
540 }
541 break;
542 }
543 case 2: // Search
544 {
545 auto * found = t.search(key);
546 bool in_oracle = oracle.count(key) > 0;
547 EXPECT_EQ(found != nullptr, in_oracle);
548 if (found)
549 EXPECT_EQ(KEY(found), key);
550 break;
551 }
552 }
553
554 ASSERT_TRUE(t.verify()) << "AVL invariant violated at op " << i;
555 }
556
557 // Final verification
558 std::vector<int> expected(oracle.begin(), oracle.end());
561}
562
563// Stress test: bulk insert then bulk remove
565{
568
569 const int n = 10000;
570
571 // Bulk insert
572 std::vector<int> keys(n);
573 std::iota(keys.begin(), keys.end(), 0);
574
575 std::mt19937 rng(12345);
576 std::shuffle(keys.begin(), keys.end(), rng);
577
578 for (int k : keys)
579 {
580 ASSERT_NE(t.insert(pool.make(k)), nullptr);
581 }
582
583 ASSERT_TRUE(t.verify());
584
585 // Bulk remove in different random order
586 std::shuffle(keys.begin(), keys.end(), rng);
587
588 for (int k : keys)
589 {
590 auto * removed = t.remove(k);
591 ASSERT_NE(removed, nullptr) << "Remove failed for key " << k;
592 pool.forget(removed);
593 delete removed;
594 ASSERT_TRUE(t.verify());
595 }
596
598}
599
600// Stress test: repeated insert_dup (duplicates allowed)
602{
605
606 const int num_keys = 100;
607 const int dups_per_key = 50;
608
609 // Insert many duplicates of each key
610 for (int k = 0; k < num_keys; ++k)
611 {
612 for (int d = 0; d < dups_per_key; ++d)
613 {
614 ASSERT_NE(t.insert_dup(pool.make(k)), nullptr);
615 }
616 }
617
618 ASSERT_TRUE(t.verify());
619
620 // Verify inorder traversal has correct count
622 EXPECT_EQ(keys.size(), num_keys * dups_per_key);
623
624 // Verify sorted
625 EXPECT_TRUE(std::is_sorted(keys.begin(), keys.end()));
626}
627
628// Stress test: alternating insert and remove
630{
633
634 std::set<int> present;
635 std::mt19937 rng(54321);
636 std::uniform_int_distribution<int> dist(0, 10000);
637
638 const int n = 15000;
639
640 for (int i = 0; i < n; ++i)
641 {
642 int k = dist(rng);
643
644 if (i % 2 == 0) // Insert
645 {
646 auto * p = pool.make(k);
647 if (t.insert(p) == nullptr)
648 {
649 pool.forget(p);
650 delete p;
651 }
652 else
653 {
655 }
656 }
657 else // Remove
658 {
659 if (auto * removed = t.remove(k); removed)
660 {
661 present.erase(k);
662 pool.forget(removed);
663 delete removed;
664 }
665 }
666
667 ASSERT_TRUE(t.verify()) << "AVL invariant violated at i=" << i;
668 }
669
670 // Final check
671 std::vector<int> expected(present.begin(), present.end());
673}
674
675// Stress test with string keys
677{
680
681 std::mt19937 rng(11111);
682 std::uniform_int_distribution<int> len_dist(1, 30);
683 std::uniform_int_distribution<int> char_dist('a', 'z');
684
685 auto random_string = [&]() {
686 int len = len_dist(rng);
687 std::string s;
688 s.reserve(len);
689 for (int i = 0; i < len; ++i)
690 s += static_cast<char>(char_dist(rng));
691 return s;
692 };
693
694 std::set<std::string> oracle;
695
696 const int n = 5000;
697
698 for (int i = 0; i < n; ++i)
699 {
700 std::string s = random_string();
701 auto * p = pool.make(s);
702 if (t.insert(p) != nullptr)
703 oracle.insert(s);
704 else
705 {
706 pool.forget(p);
707 delete p;
708 }
709 }
710
711 ASSERT_TRUE(t.verify());
712
713 // Verify all oracle strings are present
714 for (const auto & s : oracle)
715 ASSERT_NE(t.search(s), nullptr) << "String key missing: " << s;
716}
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
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
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:513
Node * search_or_insert(Node *p) noexcept
Search or insert a key.
Definition tpl_avl.H:566
Node * insert_dup(Node *p) noexcept
Insert the node p without testing for key duplicity.
Definition tpl_avl.H:589
constexpr Node *& getRoot() noexcept
Return a modifiable reference to tree's root.
Definition tpl_avl.H:506
Node * insert(Node *p) noexcept
Insert the node pointed by p in the tree.
Definition tpl_avl.H:529
bool verify() const noexcept
Definition tpl_avl.H:662
Node * remove(const Key &key) noexcept
Remove from an AVL tree the node containing key key.
Definition tpl_avl.H:608
NodeType< Key > Node
void forget(Node *p)
Definition rand-tree.cc:93
Node * make(int key)
Definition rand-tree.cc:86
iterator end() noexcept
Return an STL-compatible end iterator.
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
#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
constexpr Node *& RLINK(Node *p) noexcept
Return the right tree of p.
constexpr Node *& LLINK(Node *p) noexcept
Return a pointer to left subtree.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynList< T > maps(const C &c, Op op)
Classic map operation.
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:704
AVL tree implementation (height-balanced BST).