Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_cartesian_tree_test.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
38# include <gtest/gtest.h>
39
40# include <tpl_cartesian_tree.H>
41# include <tpl_sparse_table.H>
42
43# include <algorithm>
44# include <cstddef>
45# include <numeric>
46# include <random>
47# include <vector>
48
49using namespace Aleph;
50using namespace testing;
51
52namespace
53{
54 // ================================================================
55 // Helper: brute-force range minimum for verification
56 // ================================================================
57
58 template <typename T>
59 T brute_min(const std::vector<T> & v, size_t l, size_t r)
60 {
61 T result = v[l];
62 for (size_t i = l + 1; i <= r; ++i)
63 if (v[i] < result)
64 result = v[i];
65 return result;
66 }
67
68 template <typename T>
69 size_t brute_min_idx(const std::vector<T> & v, size_t l, size_t r)
70 {
71 size_t idx = l;
72 for (size_t i = l + 1; i <= r; ++i)
73 if (v[i] < v[idx])
74 idx = i;
75 return idx;
76 }
77
78 // Verify heap property: for every node i, comp(data[parent], data[i])
79 template <typename T, class Comp>
80 void verify_heap(const Gen_Cartesian_Tree<T, Comp> & ct, Comp c = Comp())
81 {
82 for (size_t i = 0; i < ct.size(); ++i)
83 {
84 size_t p = ct.parent_of(i);
86 EXPECT_TRUE(c(ct.data_at(p), ct.data_at(i)) ||
87 ct.data_at(p) == ct.data_at(i))
88 << "Heap violation at node " << i
89 << ": parent=" << p
90 << " data[parent]=" << ct.data_at(p)
91 << " data[i]=" << ct.data_at(i);
92 }
93 }
94
95 // Verify inorder = {0, 1, ..., n-1}
96 template <typename T, class Comp>
98 {
99 auto io = ct.inorder();
100 ASSERT_EQ(io.size(), ct.size());
101 for (size_t i = 0; i < ct.size(); ++i)
102 EXPECT_EQ(io(i), i) << "Inorder mismatch at position " << i;
103 }
104
105 // Brute-force LCA: walk from u and v to root, find common ancestor
106 template <typename T, class Comp>
108 size_t u, size_t v)
109 {
110 constexpr size_t NONE = Gen_Cartesian_Tree<T, Comp>::NONE;
111
112 // Collect ancestors of u
113 std::vector<bool> is_ancestor(ct.size(), false);
114 size_t curr = u;
115 while (curr != NONE)
116 {
117 is_ancestor[curr] = true;
118 curr = ct.parent_of(curr);
119 }
120
121 // Walk from v upward until hitting an ancestor of u
122 curr = v;
123 while (!is_ancestor[curr])
124 curr = ct.parent_of(curr);
125
126 return curr;
127 }
128
129} // anonymous namespace
130
131
132// ================================================================
133// GenCartesianTree test suite
134// ================================================================
135
137{
138 std::vector<int> empty;
139 Cartesian_Tree<int> ct(empty);
140 EXPECT_EQ(ct.size(), 0u);
141 EXPECT_TRUE(ct.is_empty());
143 auto io = ct.inorder();
144 EXPECT_EQ(io.size(), 0u);
145 EXPECT_EQ(ct.height(), 0u);
146}
147
149{
150 Cartesian_Tree<int> ct = {42};
151 EXPECT_EQ(ct.size(), 1u);
152 EXPECT_FALSE(ct.is_empty());
153 EXPECT_EQ(ct.root(), 0u);
154 EXPECT_EQ(ct.data_at(0), 42);
155 EXPECT_TRUE(ct.is_leaf(0));
156 EXPECT_TRUE(ct.is_root(0));
157 EXPECT_EQ(ct.left_child(0), Cartesian_Tree<int>::NONE);
158 EXPECT_EQ(ct.right_child(0), Cartesian_Tree<int>::NONE);
160 EXPECT_EQ(ct.height(), 1u);
162}
163
165{
166 // {5, 3} — min is 3 at index 1, so root = 1
167 Cartesian_Tree<int> ct = {5, 3};
168 EXPECT_EQ(ct.root(), 1u);
169 EXPECT_EQ(ct.left_child(1), 0u);
170 EXPECT_EQ(ct.right_child(1), Cartesian_Tree<int>::NONE);
171 verify_heap(ct);
173}
174
176{
177 Cartesian_Tree<int> ct = {3, 2, 6, 1, 9, 0, 7};
178 verify_heap(ct);
179}
180
182{
183 Cartesian_Tree<int> ct = {3, 2, 6, 1, 9, 0, 7};
185}
186
188{
189 // Array: {3, 2, 6, 1, 9}
190 // Minimum is 1 at index 3 -> root = 3
191 // Left subtree of 3 is indices {0,1,2}, min is 2 at idx 1
192 // Right subtree of 3 is index {4}
193 Cartesian_Tree<int> ct = {3, 2, 6, 1, 9};
194
195 EXPECT_EQ(ct.root(), 3u);
196 EXPECT_EQ(ct.data_at(3), 1);
197
198 // Node 1 (value 2) is left child of root 3
199 EXPECT_EQ(ct.left_child(3), 1u);
200 EXPECT_EQ(ct.right_child(3), 4u);
201
202 // Node 1 (value 2): left child is 0, right child is 2
203 EXPECT_EQ(ct.left_child(1), 0u);
204 EXPECT_EQ(ct.right_child(1), 2u);
205
206 verify_heap(ct);
208}
209
211{
212 Cartesian_Tree<int> ct = {3, 1, 4, 1, 5};
213 verify_heap(ct);
215 // Root should be one of the 1s (index 1 because of left-to-right processing)
216 EXPECT_EQ(ct.data_at(ct.root()), 1);
217}
218
220{
221 // Sorted array: Cartesian tree degenerates to left-spine
222 Cartesian_Tree<int> ct = {1, 2, 3, 4, 5};
223 EXPECT_EQ(ct.root(), 0u);
224 verify_heap(ct);
226 EXPECT_EQ(ct.height(), 5u); // chain
227}
228
230{
231 // Reverse sorted: degenerates to right-spine
232 Cartesian_Tree<int> ct = {5, 4, 3, 2, 1};
233 EXPECT_EQ(ct.root(), 4u);
234 verify_heap(ct);
236 EXPECT_EQ(ct.height(), 5u); // chain
237}
238
240{
241 Cartesian_Tree<int> ct = {7, 7, 7, 7, 7};
242 verify_heap(ct);
244}
245
247{
248 // Max-heap Cartesian Tree
249 Max_Cartesian_Tree<int> ct = {3, 2, 6, 1, 9};
250 EXPECT_EQ(ct.data_at(ct.root()), 9);
251 verify_heap(ct, Aleph::greater<int>());
253}
254
256{
257 Array<int> arr = {5, 1, 3, 2, 4};
259 EXPECT_EQ(ct.size(), 5u);
260 verify_heap(ct);
262}
263
265{
266 std::vector<int> vec = {5, 1, 3, 2, 4};
268 EXPECT_EQ(ct.size(), 5u);
269 verify_heap(ct);
271}
272
274{
275 Cartesian_Tree<int> ct = {5, 1, 3, 2, 4};
276 EXPECT_EQ(ct.size(), 5u);
277 verify_heap(ct);
279}
280
282{
283 DynList<int> dl = {5, 1, 3, 2, 4};
285 EXPECT_EQ(ct.size(), 5u);
286 verify_heap(ct);
288}
289
291{
292 // Single element: height 1
294 EXPECT_EQ(ct1.height(), 1u);
295
296 // Balanced-ish tree
297 Cartesian_Tree<int> ct2 = {2, 1, 3};
298 EXPECT_GE(ct2.height(), 2u);
299 EXPECT_LE(ct2.height(), 3u);
300}
301
303{
304 Cartesian_Tree<int> ct1 = {3, 1, 4, 1, 5};
305 Cartesian_Tree<int> ct2(ct1); // copy
306 EXPECT_EQ(ct2.root(), ct1.root());
307 EXPECT_EQ(ct2.size(), ct1.size());
308
309 Cartesian_Tree<int> ct3(std::move(ct2)); // move
310 EXPECT_EQ(ct3.root(), ct1.root());
311 EXPECT_EQ(ct3.size(), ct1.size());
312
313 Cartesian_Tree<int> ct4 = {10, 20};
314 ct4.swap(ct3);
315 EXPECT_EQ(ct4.size(), 5u);
316 EXPECT_EQ(ct3.size(), 2u);
317}
318
320{
321 Cartesian_Tree<int> ct = {3, 1, 4};
322 EXPECT_THROW(ct.data_at(3), std::out_of_range);
323 EXPECT_THROW(ct.left_child(5), std::out_of_range);
324 EXPECT_THROW(ct.right_child(100), std::out_of_range);
325 EXPECT_THROW(ct.parent_of(3), std::out_of_range);
326 EXPECT_THROW(ct.is_leaf(10), std::out_of_range);
327 EXPECT_THROW(ct.is_root(3), std::out_of_range);
328}
329
331{
332 constexpr size_t N = 1000;
333 std::mt19937 rng(42);
334 std::uniform_int_distribution<int> dist(0, 10000);
335
336 std::vector<int> v(N);
337 for (auto & x : v)
338 x = dist(rng);
339
341 EXPECT_EQ(ct.size(), N);
342 verify_heap(ct);
344}
345
346
347// ================================================================
348// EulerTourLCA test suite
349// ================================================================
350
352{
353 std::vector<int> empty;
354 Euler_Tour_LCA<int> lca(empty);
355 EXPECT_EQ(lca.size(), 0u);
356 EXPECT_TRUE(lca.is_empty());
357}
358
360{
361 Euler_Tour_LCA<int> lca = {42};
362 EXPECT_EQ(lca.size(), 1u);
363 EXPECT_EQ(lca.lca(0, 0), 0u);
364 EXPECT_EQ(lca.depth_of(0), 0u);
365 EXPECT_EQ(lca.distance(0, 0), 0u);
366}
367
369{
370 Euler_Tour_LCA<int> lca = {3, 2, 6, 1, 9};
371 // Euler tour size should be 2n - 1
372 EXPECT_EQ(lca.euler_tour_size(), 2 * 5 - 1);
373}
374
376{
377 Euler_Tour_LCA<int> lca = {3, 2, 6, 1, 9};
378 for (size_t i = 0; i < lca.size(); ++i)
379 EXPECT_EQ(lca.lca(i, i), i) << "lca(i,i) should be i for i=" << i;
380}
381
383{
384 // {3, 2, 6, 1, 9} — root is 3 (value 1)
385 // lca of any two nodes on different sides of root = root
386 Euler_Tour_LCA<int> lca = {3, 2, 6, 1, 9};
387 size_t r = lca.tree().root();
388 EXPECT_EQ(r, 3u);
389
390 // 0 is in left subtree, 4 is in right subtree
391 EXPECT_EQ(lca.lca(0, 4), r);
392 EXPECT_EQ(lca.lca(2, 4), r);
393}
394
396{
397 // {3, 2, 6, 1, 9}
398 // Tree structure:
399 // 3(1)
400 // |- 1(2)
401 // | |- 0(3)
402 // | `- 2(6)
403 // `- 4(9)
404 Euler_Tour_LCA<int> lca = {3, 2, 6, 1, 9};
405
406 // LCA(0, 2) = 1 (node with value 2, parent of both)
407 EXPECT_EQ(lca.lca(0, 2), 1u);
408
409 // LCA(0, 1) = 1 (1 is parent of 0)
410 EXPECT_EQ(lca.lca(0, 1), 1u);
411
412 // LCA(1, 4) = 3 (root)
413 EXPECT_EQ(lca.lca(1, 4), 3u);
414}
415
417{
418 // {3, 2, 6, 1, 9}
419 // Root=3 at depth 0, children 1 and 4 at depth 1, etc.
420 Euler_Tour_LCA<int> lca = {3, 2, 6, 1, 9};
421
422 EXPECT_EQ(lca.depth_of(3), 0u); // root
423 EXPECT_EQ(lca.depth_of(1), 1u); // child of root
424 EXPECT_EQ(lca.depth_of(4), 1u); // child of root
425 EXPECT_EQ(lca.depth_of(0), 2u); // grandchild
426 EXPECT_EQ(lca.depth_of(2), 2u); // grandchild
427}
428
430{
431 Euler_Tour_LCA<int> lca = {3, 2, 6, 1, 9};
432
433 // Distance(0, 2) = depth(0) + depth(2) - 2*depth(lca(0,2))
434 // = 2 + 2 - 2*1 = 2
435 EXPECT_EQ(lca.distance(0, 2), 2u);
436
437 // Distance(0, 4) = 2 + 1 - 2*0 = 3
438 EXPECT_EQ(lca.distance(0, 4), 3u);
439
440 // Distance(i, i) = 0
441 for (size_t i = 0; i < lca.size(); ++i)
442 EXPECT_EQ(lca.distance(i, i), 0u);
443}
444
446{
447 Euler_Tour_LCA<int> lca = {5, 1, 8, 3, 7, 2, 9};
448 for (size_t u = 0; u < lca.size(); ++u)
449 for (size_t v = u; v < lca.size(); ++v)
450 EXPECT_EQ(lca.lca(u, v), lca.lca(v, u))
451 << "Symmetry failed for u=" << u << " v=" << v;
452}
453
455{
456 Euler_Tour_LCA<int> lca = {3, 1, 4};
457 EXPECT_THROW(lca.lca(0, 5), std::out_of_range);
458 EXPECT_THROW(lca.lca(10, 0), std::out_of_range);
459 EXPECT_THROW(lca.depth_of(3), std::out_of_range);
460}
461
463{
464 constexpr size_t N = 500;
465 constexpr size_t Q = 2000;
466 std::mt19937 rng(123);
467 std::uniform_int_distribution<int> dist(0, 10000);
468
469 std::vector<int> v(N);
470 for (auto & x : v)
471 x = dist(rng);
472
473 Euler_Tour_LCA<int> lca(v);
474 const auto & ct = lca.tree();
475
476 std::uniform_int_distribution<size_t> idx_dist(0, N - 1);
477 for (size_t q = 0; q < Q; ++q)
478 {
479 size_t u = idx_dist(rng);
480 size_t w = idx_dist(rng);
481 size_t expected = brute_lca(ct, u, w);
482 EXPECT_EQ(lca.lca(u, w), expected)
483 << "LCA mismatch for u=" << u << " v=" << w;
484 }
485}
486
487
488// ================================================================
489// CartesianTreeRMQ test suite
490// ================================================================
491
493{
494 std::vector<int> empty;
496 EXPECT_EQ(rmq.size(), 0u);
497 EXPECT_TRUE(rmq.is_empty());
498}
499
501{
503 EXPECT_EQ(rmq.size(), 1u);
504 EXPECT_EQ(rmq.query(0, 0), 42);
505 EXPECT_EQ(rmq.query_idx(0, 0), 0u);
506 EXPECT_EQ(rmq.get(0), 42);
507}
508
510{
511 Cartesian_Tree_RMQ<int> rmq = {5, 2, 4, 7, 1, 3, 6};
512 EXPECT_EQ(rmq.query(0, 6), 1);
513 EXPECT_EQ(rmq.query_idx(0, 6), 4u);
514}
515
517{
518 Cartesian_Tree_RMQ<int> rmq = {5, 2, 4, 7, 1, 3, 6};
519 for (size_t i = 0; i < rmq.size(); ++i)
520 EXPECT_EQ(rmq.query(i, i), rmq.get(i));
521}
522
524{
525 constexpr size_t N = 100;
526 std::mt19937 rng(99);
527 std::uniform_int_distribution<int> dist(-1000, 1000);
528
529 std::vector<int> v(N);
530 for (auto & x : v)
531 x = dist(rng);
532
534 Sparse_Table<int> st(v);
535
536 // Compare all O(N^2) pairs
537 for (size_t l = 0; l < N; ++l)
538 for (size_t r = l; r < N; ++r)
539 EXPECT_EQ(rmq.query(l, r), st.query(l, r))
540 << "Mismatch at [" << l << ", " << r << "]";
541}
542
544{
545 Cartesian_Tree_RMQ<int> rmq = {5, 2, 4, 7, 1, 3, 6};
546
547 // query_idx should return position of the minimum
548 size_t idx = rmq.query_idx(0, 3);
549 EXPECT_EQ(rmq.get(idx), 2);
550 EXPECT_EQ(idx, 1u);
551
552 idx = rmq.query_idx(2, 6);
553 EXPECT_EQ(rmq.get(idx), 1);
554 EXPECT_EQ(idx, 4u);
555}
556
558{
559 Cartesian_Tree_RMaxQ<int> rmq = {5, 2, 4, 7, 1, 3, 6};
560 EXPECT_EQ(rmq.query(0, 6), 7);
561 EXPECT_EQ(rmq.query(0, 2), 5);
562 EXPECT_EQ(rmq.query(4, 6), 6);
563}
564
566{
567 constexpr size_t N = 1000;
568 constexpr size_t Q = 5000;
569 std::mt19937 rng(777);
570 std::uniform_int_distribution<int> dist(-50000, 50000);
571
572 std::vector<int> v(N);
573 for (auto & x : v)
574 x = dist(rng);
575
577
578 std::uniform_int_distribution<size_t> idx_dist(0, N - 1);
579 for (size_t q = 0; q < Q; ++q)
580 {
581 size_t l = idx_dist(rng);
582 size_t r = idx_dist(rng);
583 if (l > r)
584 std::swap(l, r);
585
586 int expected = brute_min(v, l, r);
587 EXPECT_EQ(rmq.query(l, r), expected)
588 << "Mismatch at [" << l << ", " << r << "] query " << q;
589 }
590}
591
593{
594 Cartesian_Tree_RMQ<int> rmq = {3, 1, 4};
595 EXPECT_THROW(rmq.query(0, 5), std::out_of_range);
596 EXPECT_THROW(rmq.query(2, 1), std::out_of_range);
597 EXPECT_THROW(rmq.get(3), std::out_of_range);
598}
long double w
Definition btreepic.C:153
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
Dynamic singly linked list with functional programming support.
Definition htlist.H:1155
size_t query_idx(const size_t l, const size_t r) const
Return the index of the optimal element in a[l..r].
Explicit Cartesian Tree built in O(n) with a monotonic stack.
void swap(Gen_Cartesian_Tree &other) noexcept(noexcept(data_.swap(other.data_)) &&noexcept(parent_.swap(other.parent_)) &&noexcept(left_.swap(other.left_)) &&noexcept(right_.swap(other.right_)) &&noexcept(std::swap(root_, other.root_)) &&noexcept(std::swap(n_, other.n_)) &&std::is_nothrow_swappable_v< Comp >)
Swap with other in O(1).
constexpr size_t root() const noexcept
Index of the root node.
size_t euler_tour_size() const noexcept
Size of the Euler Tour (should be 2n-1 for n > 0).
constexpr size_t size() const noexcept
Number of nodes.
const Gen_Cartesian_Tree< T, Comp > & tree() const noexcept
Const reference to the internal Cartesian Tree.
size_t depth_of(const size_t u) const
Depth of node u in the Cartesian Tree.
constexpr bool is_empty() const noexcept
True if empty.
size_t lca(const size_t u, const size_t v) const
Lowest Common Ancestor of nodes u and v in O(1).
size_t distance(const size_t u, const size_t v) const
Distance between nodes u and v in the tree.
T query(const size_t l, const size_t r) const
Range query over [l, r] in O(1).
#define TEST(name)
static mt19937 rng
T brute_min(const vector< T > &v, size_t l, size_t r)
#define N
Definition fib.C:294
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::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
Range minimum queries via Cartesian Tree.
Range maximum queries via Cartesian Tree.
Cartesian Tree for min-heap (range minimum).
LCA on a min-heap Cartesian Tree.
Cartesian Tree for max-heap (range maximum).
Sparse Table for range minimum queries.
Distance accessor.
gsl_rng * r
Cartesian Tree, LCA via Euler Tour, and RMQ via Cartesian Tree.
Sparse Table for static range queries in O(1).
DynList< int > l