Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
rb_tree_test.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
45#include <algorithm>
46#include <random>
47#include <set>
48#include <vector>
49
50#include <gtest/gtest.h>
51
52#include <tpl_rb_tree.H>
53
54using namespace Aleph;
55using namespace testing;
56
57namespace
58{
59 // Helper to manage node allocation
60 template <class Tree>
61 struct NodePool
62 {
63 using Node = typename Tree::Node;
64
65 std::vector<Node *> allocated;
66
67 Node * make(const typename Node::key_type & key)
68 {
69 Node * p = new Node(key);
70 allocated.push_back(p);
71 return p;
72 }
73
74 void forget(Node * p) noexcept
75 {
76 for (auto & q : allocated)
77 if (q == p)
78 {
79 q = nullptr;
80 return;
81 }
82 }
83
84 ~NodePool()
85 {
86 for (Node * p : allocated)
87 delete p;
88 }
89 };
90
91 // Collect keys in inorder traversal
92 template <class Node>
93 std::vector<typename Node::key_type> inorder_keys(Node * root)
94 {
95 std::vector<typename Node::key_type> keys;
96 if (root == nullptr || root == Node::NullPtr)
97 return keys;
98
99 auto left = inorder_keys(LLINK(root));
100 keys.insert(keys.end(), left.begin(), left.end());
101 keys.push_back(KEY(root));
102 auto right = inorder_keys(RLINK(root));
103 keys.insert(keys.end(), right.begin(), right.end());
104
105 return keys;
106 }
107
108
109 // Verify all Red-Black properties using tree's built-in verify
110 template <class Tree>
111 bool verify_rb_properties(Tree & tree)
112 {
113 return tree.verify();
114 }
115}
116
117// =============================================================================
118// Test Fixtures
119// =============================================================================
120
121class RbTreeTest : public Test
122{
123protected:
126
129
130 void insert_values(std::initializer_list<int> values)
131 {
132 for (int v : values)
133 tree.insert(pool.make(v));
134 }
135};
136
137// =============================================================================
138// Basic Operations Tests
139// =============================================================================
140
142{
143 EXPECT_EQ(tree.size(), 0);
144 EXPECT_TRUE(tree.is_empty());
145}
146
148{
149 tree.insert(pool.make(10));
150 EXPECT_EQ(tree.size(), 1);
151 EXPECT_FALSE(tree.is_empty());
152
153 tree.insert(pool.make(5));
154 tree.insert(pool.make(15));
155 EXPECT_EQ(tree.size(), 3);
156}
157
159{
160 insert_values({50, 25, 75, 10, 30, 60, 90});
161
162 EXPECT_NE(tree.search(50), nullptr);
163 EXPECT_NE(tree.search(25), nullptr);
164 EXPECT_NE(tree.search(75), nullptr);
165 EXPECT_NE(tree.search(10), nullptr);
166
167 EXPECT_EQ(tree.search(100), nullptr);
168 EXPECT_EQ(tree.search(0), nullptr);
169}
170
172{
173 insert_values({50, 25, 75});
174 EXPECT_EQ(tree.size(), 3);
175
176 Node * removed = tree.remove(25);
177 EXPECT_NE(removed, nullptr);
178 EXPECT_EQ(tree.size(), 2);
179 EXPECT_EQ(tree.search(25), nullptr);
180
181 pool.forget(removed);
182 delete removed;
183}
184
186{
187 insert_values({50, 25, 75});
188
189 Node * removed = tree.remove(100);
190 EXPECT_EQ(removed, nullptr);
191 EXPECT_EQ(tree.size(), 3);
192}
193
194// =============================================================================
195// Red-Black Properties Tests
196// =============================================================================
197
199{
200 tree.insert(pool.make(50));
202}
203
205{
206 insert_values({50, 25, 75, 10, 30, 60, 90, 5, 15, 27, 35});
208}
209
211{
212 // Sequential inserts often trigger many rotations
213 for (int i = 1; i <= 20; ++i)
214 tree.insert(pool.make(i));
215
217 EXPECT_EQ(tree.size(), 20);
218}
219
221{
222 for (int i = 20; i >= 1; --i)
223 tree.insert(pool.make(i));
224
226 EXPECT_EQ(tree.size(), 20);
227}
228
230{
231 insert_values({50, 25, 75, 10, 30, 60, 90});
233
234 Node * removed = tree.remove(25);
235 pool.forget(removed);
236 delete removed;
237
239}
240
242{
243 std::vector<int> values = {50, 25, 75, 10, 30, 60, 90, 5, 15, 27, 35};
244 for (int v : values)
245 tree.insert(pool.make(v));
246
247 // Remove half the values
248 for (int v : {25, 60, 5, 30, 75})
249 {
250 Node * removed = tree.remove(v);
251 if (removed)
252 {
253 pool.forget(removed);
254 delete removed;
255 }
257 }
258}
259
260// =============================================================================
261// Ordering Tests
262// =============================================================================
263
265{
266 insert_values({50, 25, 75, 10, 30, 60, 90});
267
268 auto keys = inorder_keys(tree.getRoot());
269
270 EXPECT_TRUE(std::is_sorted(keys.begin(), keys.end()));
271 EXPECT_EQ(keys.size(), 7);
272}
273
275{
276 insert_values({50, 25, 75, 10, 30, 60, 90});
277
278 auto keys = inorder_keys(tree.getRoot());
279
280 EXPECT_EQ(keys.front(), 10); // Min
281 EXPECT_EQ(keys.back(), 90); // Max
282}
283
284// =============================================================================
285// Stress Tests
286// =============================================================================
287
289{
290 std::mt19937 rng(42);
291 std::uniform_int_distribution<int> dist(1, 10000);
292 std::set<int> inserted;
293
294 for (int i = 0; i < 1000; ++i)
295 {
296 int value = dist(rng);
297 if (inserted.insert(value).second)
298 tree.insert(pool.make(value));
299 }
300
302 EXPECT_EQ(tree.size(), inserted.size());
303}
304
306{
307 std::mt19937 rng(123);
308 std::uniform_int_distribution<int> dist(1, 1000);
309 std::vector<int> values;
310
311 // Insert 500 random values
312 for (int i = 0; i < 500; ++i)
313 {
314 int value = dist(rng);
315 values.push_back(value);
316 tree.insert(pool.make(value));
317 }
318
320
321 // Remove half of them
322 std::shuffle(values.begin(), values.end(), rng);
323 for (size_t i = 0; i < values.size() / 2; ++i)
324 {
325 Node * removed = tree.remove(values[i]);
326 if (removed)
327 {
328 pool.forget(removed);
329 delete removed;
330 }
331 }
332
334}
335
336// =============================================================================
337// Height Tests
338// =============================================================================
339
341{
342 // Insert 1000 sequential elements
343 for (int i = 1; i <= 1000; ++i)
344 tree.insert(pool.make(i));
345
346 // RB tree height <= 2 * log2(n+1)
347 // For n=1000: max height ~= 20
348 size_t n = tree.size();
349
350 // Verify the tree is valid (which validates logarithmic structure)
352 EXPECT_EQ(n, 1000);
353}
354
355// =============================================================================
356// Regression: candidate_pos == rb_stack.size() (zero-pop branch)
357// =============================================================================
358
359// When the duplicate key equals the current maximum, every descent goes
360// right so candidate_pos equals rb_stack.size() at loop exit, making
361// to_pop == 0 and rb_stack.popn() is never called.
363{
364 // Right-spine: 10 -> 20 -> 30. 30 is the current maximum.
365 insert_values({10, 20, 30});
367
368 // Duplicate of maximum: candidate_pos == rb_stack.size(), to_pop == 0.
369 Node * dup = pool.make(30);
370 Node * res = tree.insert(dup);
371 EXPECT_EQ(res, nullptr);
372 pool.forget(dup);
373 delete dup;
374
376 EXPECT_EQ(tree.size(), 3);
377}
378
379// Randomised variant: build trees of increasing size and insert a
380// duplicate of the maximum to reliably exercise the zero-pop path.
382{
383 std::mt19937 rng(54321);
384 std::uniform_int_distribution<int> n_dist(1, 50);
385
386 for (int trial = 0; trial < 200; ++trial)
387 {
388 Tree t;
390
391 int n = n_dist(rng);
392 for (int i = 1; i <= n; ++i)
393 t.insert(lpool.make(i));
394
395 // Insert duplicate of current maximum
396 Node * dup = lpool.make(n);
397 Node * res = t.insert(dup);
398 EXPECT_EQ(res, nullptr) << "trial " << trial;
399 lpool.forget(dup);
400 delete dup;
401
402 ASSERT_TRUE(verify_rb_properties(t)) << "trial " << trial;
403 }
404}
405
406// =============================================================================
407// Main
408// =============================================================================
409
410int main(int argc, char **argv)
411{
413 return RUN_ALL_TESTS();
414}
WeightedDigraph::Node Node
@ KEY
Definition btreepic.C:169
Node * insert(Node *p) noexcept
Insert a node into the tree.
NodeType< Key > Node
void forget(Node *p)
Definition rand-tree.cc:93
Node * make(int key)
Definition rand-tree.cc:86
Node for QuadTree spatial data structure.
Definition quadnode.H:94
QuadTree - Hierarchical spatial index for 2D points.
Definition quadtree.H:126
QuadNode Node
Definition quadtree.H:128
Point * insert(Node *&r, const Point &p)
Recursive insert helper.
Definition quadtree.H:237
void insert_values(std::initializer_list< int > values)
NodePool< Tree > pool
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
TEST_F(RbTreeTest, EmptyTreeHasZeroSize)
#define RLINK(i, n)
int keys[]
#define LLINK(i, n)
Dnode< int > Test
Definition testDnode.C:37
Red-Black tree implementation (bottom-up balancing).