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// Main
357// =============================================================================
358
359int main(int argc, char **argv)
360{
362 return RUN_ALL_TESTS();
363}
int main()
WeightedDigraph::Node Node
@ KEY
Definition btreepic.C:169
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
T remove()
Remove the first item of the list.
Definition htlist.H:1611
bool verify() const
Return true if this is a consistent randomized tree.
NodeType< Key > Node
Node * insert(Node *p) noexcept
Insert a node into the tree.
NodeType< Key > Node
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
void forget(Node *p)
Definition rand-tree.cc:93
Node * make(int key)
Definition rand-tree.cc:86
void insert_values(std::initializer_list< int > values)
NodePool< Tree > pool
Tree::Node Node
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
TEST_F(RbTreeTest, EmptyTreeHasZeroSize)
Red-Black tree implementation (bottom-up balancing).