Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
prefix-tree.H
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
48#ifndef PREFIX_TREE_H
49#define PREFIX_TREE_H
50
51# include <tpl_tree_node.H>
52# include <tpl_dynArray.H>
53# include <tpl_dynList.H>
54# include <tpl_arrayStack.H>
55# include <ah-errors.H>
56
57namespace Aleph
58{
110 class Cnode : public Tree_Node<char>
111 {
112 public:
117 explicit Cnode(const char c) noexcept
118 {
119 this->get_key() = c;
120 }
121
126 [[nodiscard]] char symbol() const noexcept { return get_key(); }
127
136 {
139 {
140 r.append(static_cast<Cnode *>(p));
141 });
142 return r;
143 }
144
149 [[nodiscard]] std::string to_str() const
150 {
151 std::string ret(1, symbol());
152 children().for_each([&ret](Cnode *p)
153 {
154 ret += "(" + p->to_str() + ")";
155 });
156 return ret;
157 }
158
166 {
168 if (child == nullptr)
169 return false;
170 return child->get_key() == '$';
171 }
172
180 {
183 }
184
190 [[nodiscard]] Cnode * search_child(const char c) const noexcept
191 {
192 for (Tree_Node<char> *child = get_left_child(); child != nullptr;
193 child = child->get_right_sibling())
194 if (child->get_key() == c)
195 return static_cast<Cnode *>(child);
196
197 return nullptr;
198 }
199
207 [[nodiscard]] Cnode * greater_child(const char c) const noexcept
208 {
209 for (Tree_Node<char> *child = get_left_child(); child != nullptr;
210 child = child->get_right_sibling())
211 if (child->get_key() > c)
212 return static_cast<Cnode *>(child);
213 return nullptr;
214 }
215
224 [[nodiscard]] std::tuple<const Cnode *, const char *>
225 search_prefix(const char *prefix) const noexcept
226 {
227 assert(prefix != nullptr);
228
229 if (*prefix == '\0')
230 return std::make_tuple(this, "");
231
232 const Cnode *p = search_child(*prefix);
233 if (p == nullptr)
234 return std::make_tuple(this, prefix);
235
236 return p->search_prefix(prefix + 1);
237 }
238
244 [[nodiscard]] const Cnode * search_word(const char *word) const noexcept
245 {
246 if (*word == '\0')
247 return is_end_word() ? this : nullptr;
248
249 const Cnode *ptr = search_child(*word);
250 if (ptr == nullptr)
251 return nullptr;
252
253 return ptr->search_word(word + 1);
254 }
255
261 [[nodiscard]] bool contains(const std::string & word) const noexcept
262 {
263 return search_word(word.c_str()) != nullptr;
264 }
265
271 {
272 size_t n = is_end_word() ? 1 : 0;
273 for_each_child([&n](const Tree_Node<char> *p)
274 {
275 n += static_cast<const Cnode *>(p)->count();
276 });
277 return n;
278 }
279
287 const std::string & prefix,
288 const size_t max_word_length = 2048) const
289 {
290 auto [node, remaining] = search_prefix(prefix.c_str());
291
292 // Prefix not fully matched
293 if (*remaining != '\0')
294 return {};
295
296 // Get all words from the prefix node and prepend the prefix
299
300 // Push prefix (except last char which will be pushed by words_impl)
301 for (size_t i = 0; i + 1 < prefix.size(); ++i)
302 stack.push(prefix[i]);
303
304 node->words_impl(stack, ret_val);
305 return ret_val;
306 }
307
318 {
319 assert(search_child(child->symbol()) == nullptr);
320
321 if (Cnode *sibling = greater_child(child->symbol()); sibling == nullptr)
322 this->insert_rightmost_child(child);
323 else
324 sibling->insert_left_sibling(child);
325
326 return child;
327 }
328
338 bool insert_word(const std::string & word)
339 {
340 auto [pp, rem] = search_prefix(word.c_str());
341
342 if (*rem == '\0')
343 {
344 if (pp->is_end_word())
345 return false;
346 const_cast<Cnode *>(pp)->mark_end_word();
347 return true;
348 }
349
350 // Insert nodes directly without intermediate list
351 auto *parent = const_cast<Cnode *>(pp);
352 for (const char *ptr = rem; *ptr; ++ptr)
353 parent = parent->insert_child(new Cnode(*ptr));
354
355 parent->mark_end_word();
356 return true;
357 }
358
365 {
366 // Must copy children list first - can't iterate while deleting
367 children().for_each([](Cnode *p) { destroy_tree(p); });
368 }
369
370 private:
371 static std::string extract_word_from_stack(FixedStack<char> & stack)
372 {
373 std::string ret_val;
374 ret_val.reserve(stack.size());
375
376 const char *ptr = &stack.base();
377 const char *last = &stack.top();
378 while (ptr <= last)
379 ret_val.append(1, *ptr++);
380
381 return ret_val;
382 }
383
385 {
386 if (symbol() == '$')
388
389 stack.push(symbol());
390
391 for (const Tree_Node<char> *child = get_left_child(); child != nullptr;
392 child = child->get_right_sibling())
393 static_cast<const Cnode *>(child)->words_impl(stack, l);
394
395 stack.pop();
396 }
397
398 public:
407 {
410
412 {
413 static_cast<const Cnode *>(p)->words_impl(stack, ret_val);
414 });
415
416 return ret_val;
417 }
418
423 void print_words(const size_t max_word_length = 2048) const
424 {
425 words(max_word_length).for_each([](const std::string & w)
426 {
427 std::cout << w << '\n';
428 });
429 }
430
436 static void clone(const Tree_Node<char> *src, Tree_Node<char> *tgt)
437 {
438 // First, create all children in target
439 src->for_each_child([tgt](auto s)
440 {
441 tgt->insert_rightmost_child(new Cnode(s->get_key()));
442 });
443
444 // Then recursively clone each child subtree
447 while (src_child != nullptr)
448 {
450 src_child = src_child->get_right_sibling();
451 tgt_child = tgt_child->get_right_sibling();
452 }
453 }
454
461 [[nodiscard]] Cnode * clone() const
462 {
463 auto *ret = new Cnode(symbol());
464 clone(this, ret);
465 return ret;
466 }
467 };
468} // end namespace Aleph
469
470#endif // PREFIX_TREE_H
Exception handling system with formatted messages for Aleph-w.
long double w
Definition btreepic.C:153
Prefix tree (Trie) node for storing character sequences.
Cnode(const char c) noexcept
Construct a node with the given character.
static std::string extract_word_from_stack(FixedStack< char > &stack)
size_t count() const noexcept
Count total words stored in this subtree.
static void clone(const Tree_Node< char > *src, Tree_Node< char > *tgt)
Clone helper - copies children from src to tgt.
Cnode * clone() const
Create a deep copy of this subtree.
bool contains(const std::string &word) const noexcept
Check if a word exists in the tree.
void destroy() noexcept
Destroy all children of this node.
void words_impl(FixedStack< char > &stack, DynArray< std::string > &l) const
std::string to_str() const
Convert the subtree to a string representation.
std::tuple< const Cnode *, const char * > search_prefix(const char *prefix) const noexcept
Search for a prefix in the tree.
const Cnode * search_word(const char *word) const noexcept
Search for a complete word in the tree.
void mark_end_word()
Mark this node as the end of a word.
void print_words(const size_t max_word_length=2048) const
Print all words to stdout.
bool is_end_word() const noexcept
Check if this node marks the end of a word.
Cnode * insert_child(Cnode *child)
Insert a child node in sorted order.
char symbol() const noexcept
Return the character stored in this node.
bool insert_word(const std::string &word)
Insert a word into the tree.
Cnode * search_child(const char c) const noexcept
Search for a child with the given character.
Cnode * greater_child(const char c) const noexcept
Find the first child with a character greater than c.
DynArray< std::string > words(size_t max_word_length=2048) const
Get all words stored in this subtree.
DynArray< std::string > words_with_prefix(const std::string &prefix, const size_t max_word_length=2048) const
Get all words starting with a given prefix.
DynList< Cnode * > children() const
Return a list of all child nodes.
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
Fixed length stack.
T & push(const T &data) noexcept
Push a copy of data
size_t size() const noexcept
Return the number of elements stored in the stack.
T & base() const noexcept
Return the internal array base.
T & top() const noexcept
Return a modifiable referemce to stack's top.
T pop() noexcept
Pop by moving the top of stack.
Container< __Type > maps(Operation &operation) const
Transform elements using a mapping function.
const Type * last() const
Get the last element.
Generic m-ary trees.
Tree_Node * get_left_child() const noexcept
Returns the leftmost child of this.
void insert_leftmost_child(Tree_Node *p) noexcept
Inserts p as the leftmost child of this.
void insert_rightmost_child(Tree_Node *p) noexcept
Inserts p as the rightmost child of this.
void for_each_child(Operation &op) const
Visits each child of this and executes the operation on the child node.
char & get_key() noexcept
Returns a modifiable reference to the node contents.
void destroy_tree(Node *root)
Destroys (frees memory) the tree whose root is root.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
static void prefix(Node *root, DynList< Node * > &acc)
Stack implementations backed by dynamic or fixed arrays.
Lazy and scalable dynamic array implementation.
Alias for htlist.H (DynList implementation).
General tree (n-ary tree) node.
DynList< int > l