Aleph-w  1.9
General library for algorithms and data structures
tpl_rb_tree.H
1 
2 /* Aleph-w
3 
4  / \ | | ___ _ __ | |__ __ __
5  / _ \ | |/ _ \ '_ \| '_ \ ____\ \ /\ / / Data structures & Algorithms
6  / ___ \| | __/ |_) | | | |_____\ V V / version 1.9b
7  /_/ \_\_|\___| .__/|_| |_| \_/\_/ https://github.com/lrleon/Aleph-w
8  |_|
9 
10  This file is part of Aleph-w library
11 
12  Copyright (c) 2002-2018 Leandro Rabindranath Leon & Alejandro Mujica
13 
14  This program is free software: you can redistribute it and/or modify
15  it under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  This program is distributed in the hope that it will be useful, but
20  WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with this program. If not, see <https://www.gnu.org/licenses/>.
26 */
27 
28 # ifndef TPL_RB_TREE_H
29 # define TPL_RB_TREE_H
30 
31 # include <ahFunction.H>
32 # include <tpl_arrayStack.H>
33 # include <tpl_binNodeUtils.H>
34 # include <rbNode.H>
35 
36 using namespace Aleph;
37 
38 namespace Aleph {
39 
59  template <template <typename> class NodeType, typename Key, class Compare>
61 {
62 public:
63 
64  typedef NodeType<Key> Node;
65 
66 private:
67 
68  Node head_node; // cabecera centinela
69  Node * head; // puntero a centinela
70  Node *& root;
71  FixedStack<Node*> rb_stack;
72  Compare cmp;
73 
74  Node * search_and_stack_rb(const Key & key)
75  {
76  Node * p = root;
77  rb_stack.push(head);
78  do
79  {
80  rb_stack.push(p);
81  if (cmp(key, KEY(p)))
82  p = LLINK(p);
83  else if (cmp(KEY(p), key))
84  p = RLINK(p);
85  else
86  return p;
87  }
88  while (p != Node::NullPtr);
89 
90  return rb_stack.top();
91  }
92 
93  Node * search_dup_and_stack_rb(const Key & key)
94  {
95  Node * p = root;
96  rb_stack.push(head);
97  do
98  {
99  rb_stack.push(p);
100  if (cmp(key, KEY(p)))
101  p = LLINK(p);
102  else
103  p = RLINK(p);
104  }
105  while (p != Node::NullPtr);
106 
107  return rb_stack.top();
108  }
109 
110  void fix_red_condition(Node * p)
111  {
112  assert(COLOR(p) == RED);
113 
114  while (p != root)
115  {
116  Node * pp = rb_stack.pop(); // padre de p
117  if (COLOR(pp) == BLACK) // ¿padre de p negro?
118  break; // sí ==> no hay rojos consecutivos ==> terminar
119 
120  if (root == pp) // ¿p es hijo directo de la raíz?
121  { // sí ==> colorear raíz de negro y terminar
122  COLOR(root) = BLACK;
123  break;
124  }
125 
126  Node * ppp = rb_stack.pop(); // abuelo de p
127  Node * spp = LLINK(ppp) == pp ? RLINK(ppp) : LLINK(ppp); // tío
128  if (COLOR(spp) == RED) // ¿tío de p rojo?
129  { // intercambiar colores entre los niveles
130  COLOR(ppp) = RED;
131  COLOR(pp) = BLACK;
132  COLOR(spp) = BLACK;
133  p = ppp;
134  continue; // ir próximo ancestro, verificar violaciones
135  }
136 
137  Node * pppp = rb_stack.pop(); // bisabuelo de p
138  if (LLINK(pp) == p and LLINK(ppp) == pp)
139  {
140  rotate_to_right(ppp, pppp);
141  COLOR(pp) = BLACK;
142  }
143  else if (RLINK(pp) == p and RLINK(ppp) == pp)
144  {
145  rotate_to_left(ppp, pppp);
146  COLOR(pp) = BLACK;
147  }
148  else
149  {
150  if (RLINK(pp) == p)
151  {
152  rotate_to_left(pp, ppp);
153  rotate_to_right(ppp, pppp);
154  }
155  else
156  {
157  rotate_to_right(pp, ppp);
158  rotate_to_left(ppp, pppp);
159  }
160  COLOR(p) = BLACK;
161  }
162 
163  COLOR(ppp) = RED;
164  break; // árbol es rojo-negro ==> terminar
165  }
166 
167  rb_stack.empty();
168  }
169 
170  void find_succ_and_swap(Node * p, Node *& pp)
171  {
172  Node *& ref_rb_stack = rb_stack.top();
173 
174  /* Find successor while updating rb_stack */
175  Node * fSucc = p; // successor's parent
176  Node * succ = RLINK(p); // Searching starts from p's right child
177  rb_stack.push(succ);
178 
179  while (LLINK(succ) != Node::NullPtr) // go down to leftmost
180  {
181  fSucc = succ;
182  succ = LLINK(succ);
183  rb_stack.push(succ);
184  }
185 
186  ref_rb_stack = succ; /* swap old top with current top */
187  rb_stack.top() = p;
188 
189  if (LLINK(pp) == p) /* Setting of parent of p to new child(succ) */
190  LLINK(pp) = succ;
191  else
192  RLINK(pp) = succ;
193 
194  LLINK(succ) = LLINK(p); /* Swaps left branches */
195  LLINK(p) = Node::NullPtr;
196 
197  if (RLINK(p) == succ) /* For right branches there are two cases */
198  { /* successor is just right child of p */
199  RLINK(p) = RLINK(succ);
200  RLINK(succ) = p;
201  pp = succ;
202  }
203  else
204  { /* Successor is leftmost node descending from right child of p */
205  Node *succr = RLINK(succ);
206  RLINK(succ) = RLINK(p);
207  LLINK(fSucc) = p;
208  RLINK(p) = succr;
209  pp = fSucc;
210  }
211 
212  std::swap(COLOR(succ), COLOR(p));
213  }
214 
215  void fix_black_condition(Node * p)
216  {
217  if (COLOR(p) == RED) // ¿p es rojo?
218  { // sí ==> lo pintamos de negro y terminamos
219  COLOR(p) = BLACK; // esto compensa el déficit
220  return;
221  }
222 
223  Node * pp = rb_stack.popn(2); // padre de p
224  while (p != root)
225  {
226  assert(LLINK(pp) == p or RLINK(pp) == p);
227  assert(LLINK(rb_stack.top()) == pp or RLINK(rb_stack.top()) == pp);
228 
229  Node * sp = LLINK(pp) == p ? RLINK(pp) : LLINK(pp); // hermano p
230  if (COLOR(sp) == RED) // ¿hermano de p es rojo?
231  {
232  Node *& ppp = rb_stack.top(); // abuelo de p
233 
234  if (LLINK(pp) == p)
235  {
236  sp = LLINK(sp);
237  ppp = rotate_to_left(pp, ppp);
238  }
239  else
240  {
241  sp = RLINK(sp);
242  ppp = rotate_to_right(pp, ppp);
243  }
244 
245  COLOR(ppp) = BLACK;
246  COLOR(pp) = RED;
247  }
248 
249  Node * np, * snp; // sobrinos de nodo p
250  if (LLINK(pp) == p) // ¿p es hijo izquierdo?
251  { // sí ==> que sp es hijo derechos
252  np = RLINK(sp);
253  snp = LLINK(sp);
254  }
255  else
256  {
257  np = LLINK(sp);
258  snp = RLINK(sp);
259  }
260 
261  if (COLOR(np) == RED) // ¿np es rojo?
262  {
263  Node * ppp = rb_stack.top();
264 
265  if (RLINK(sp) == np)
266  rotate_to_left(pp, ppp);
267  else
268  rotate_to_right(pp, ppp);
269 
270  COLOR(sp) = COLOR(pp);
271  COLOR(pp) = BLACK;
272  COLOR(np) = BLACK;
273 
274  return;
275  }
276 
277  if (COLOR(snp) == RED) // ¿snp es rojo?
278  {
279  Node * ppp = rb_stack.top();
280 
281  if (LLINK(sp) == snp)
282  {
283  rotate_to_right(sp, pp);
284  rotate_to_left(pp, ppp);
285  }
286  else
287  {
288  rotate_to_left(sp, pp);
289  rotate_to_right(pp, ppp);
290  }
291 
292  COLOR(snp) = COLOR(pp);
293  COLOR(pp) = BLACK;;
294 
295  return;
296  }
297 
298  if (COLOR(pp) == RED) // ¿pp es rojo?
299  {
300  COLOR(pp) = BLACK;
301  COLOR(sp) = RED;;
302  return;
303  }
304 
305  // no hay nodo rojo en las adyacencias de p ==> desplazar el
306  // déficit hacia pp y repetir la iteración
307  COLOR(sp) = RED;
308  p = pp;
309  pp = rb_stack.pop();
310  }
311  }
312 
313 public:
314 
316  typedef Key key_type;
317 
319  Compare & key_comp() { return cmp; }
320 
322  Compare & get_compare() { return key_comp(); }
323 
325  Gen_Rb_Tree(Compare __cmp = Compare())
326  : head(&head_node), root(head_node.getR()),
327  rb_stack(Node::MaxHeight), cmp(__cmp)
328  {
329  /* empty */
330  }
331 
337  void swap (Gen_Rb_Tree & tree)
338  {
339  std::swap(root, tree.root);
340  std::swap(cmp, tree.cmp);
341  }
342 
344  virtual ~Gen_Rb_Tree() { /* empty */ }
345 
349  Node * search(const Key & key)
350  {
351  Node * retVal = Aleph::searchInBinTree <Node, Compare> (root, key, cmp);
352  return retVal == Node::NullPtr ? nullptr : retVal;
353  }
354 
356  Node *& getRoot() { return root; }
361  Node * insert(Node * p)
362  {
363  assert(COLOR(p) == RED);
364 
365  if (root == Node::NullPtr)
366  return root = p; // inserción en árbol vacío
367 
368  Node * q = search_and_stack_rb(KEY(p));
369  if (cmp(KEY(p), KEY(q)))
370  LLINK(q) = p;
371  else if (cmp(KEY(q), KEY(p)))
372  RLINK(q) = p;
373  else
374  {
375  rb_stack.empty();
376  return nullptr; // clave duplicada
377  }
378  fix_red_condition(p);
379 
380  return p;
381  }
382 
397  Node * search_or_insert(Node * p)
398  {
399  assert(COLOR(p) == RED);
400 
401  if (root == Node::NullPtr)
402  return root = p; // inserción en árbol vacío
403 
404  Node * q = search_and_stack_rb(KEY(p));
405  if (cmp(KEY(p), KEY(q)))
406  LLINK(q) = p;
407  else if (cmp(KEY(q), KEY(p)))
408  RLINK(q) = p;
409  else
410  {
411  rb_stack.empty();
412  return q; // clave duplicada
413  }
414  fix_red_condition(p);
415 
416  return p;
417  }
418 
423  Node * insert_dup(Node * p)
424  {
425  assert(COLOR(p) == RED);
426 
427  if (root == Node::NullPtr)
428  return root = p; // inserción en árbol vacío
429 
430  Node * q = search_dup_and_stack_rb(KEY(p));
431  if (cmp(KEY(p), KEY(q)))
432  LLINK(q) = p;
433  else
434  RLINK(q) = p;
435 
436  fix_red_condition(p);
437 
438  return p;
439  }
440 
441  bool verify() const { return is_red_black_tree(root) ; }
442 
447  Node* remove(const Key & key)
448  {
449  if (root == Node::NullPtr)
450  return nullptr;
451 
452  Node * q = search_and_stack_rb(key);
453  if (no_equals<Key, Compare> (KEY(q), key, cmp)) // ¿clave no encontrada?
454  {
455  rb_stack.empty();
456  return nullptr;
457  }
458 
459  Node * pq = rb_stack.top(1); // padre de 1
460  Node * p; // hijo de q luego de que éste ha sido eliminado
461  while (true) // eliminación clásica árbol binario de búsqueda
462  {
463  if (LLINK(q) == Node::NullPtr)
464  {
465  if (LLINK(pq) == q)
466  p = LLINK(pq) = RLINK(q);
467  else
468  p = RLINK(pq) = RLINK(q);
469 
470  break; // goto end;
471  }
472 
473  if (RLINK(q) == Node::NullPtr)
474  {
475  if (LLINK(pq) == q)
476  p = LLINK(pq) = LLINK(q);
477  else
478  p = RLINK(pq) = LLINK(q);
479 
480  break; // goto end;
481  }
482 
483  find_succ_and_swap(q, pq);
484  }
485 
486  if (COLOR(q) == BLACK) // ¿se eliminó un nodo negro?
487  fix_black_condition(p);
488 
489  q->reset();
490  rb_stack.empty();
491 
492  return q;
493  }
494 
503  struct Iterator : public BinNodeInfixIterator<Node>
504  {
506  };
507 };
522  template <typename Key, class Compare = Aleph::less<Key>>
523 struct Rb_Tree : public Gen_Rb_Tree<RbNode, Key, Compare>
524 {
526  using Base::Base;
527 };
528 
544  template <typename Key, class Compare = Aleph::less<Key>>
545 struct Rb_Tree_Vtl : public Gen_Rb_Tree<RbNodeVtl, Key, Compare>
546 {
548  using Base::Base;
549 };
550 
551 } // end namespace Aleph
552 
553 # endif // TPL_RB_TREE_H
554 
Definition: tpl_binNodeUtils.H:2445
void swap(Gen_Rb_Tree &tree)
Definition: tpl_rb_tree.H:337
Key key_type
El tipo de clave que contiene el nodo.
Definition: tpl_rb_tree.H:316
Node *& getRoot()
Obtiene un puntero a la raíz del árbol.
Definition: tpl_rb_tree.H:356
Node * rotate_to_right(Node *p) noexcept
Definition: tpl_binNodeUtils.H:1891
Definition: tpl_rb_tree.H:523
Definition: tpl_rb_tree.H:545
Definition: tpl_rb_tree.H:60
T pop() noexcept
Pop by moving the top of stack.
Definition: tpl_arrayStack.H:430
Node * search_or_insert(Node *p)
Definition: tpl_rb_tree.H:397
T popn(const int &n) noexcept
Definition: tpl_arrayStack.H:442
Node::Key_Type & KEY(Node *p) noexcept
Definition: tpl_binNode.H:318
T & top() const noexcept
Return a modifiable referemce to stack&#39;s top.
Definition: tpl_arrayStack.H:451
Definition: ah-comb.H:35
Gen_Rb_Tree(Compare __cmp=Compare())
Instancia un árbol rojo-negro.
Definition: tpl_rb_tree.H:325
Compare & get_compare()
Definition: tpl_rb_tree.H:322
Definition: tpl_arrayStack.H:302
Node *& LLINK(Node *p) noexcept
Definition: tpl_binNode.H:298
Compare & key_comp()
Retorna una referencia al criterio de comparación.
Definition: tpl_rb_tree.H:319
Node * insert_dup(Node *p)
Definition: tpl_rb_tree.H:423
void empty() noexcept
Empty the stack.
Definition: tpl_arrayStack.H:480
T & push(const T &data) noexcept
Definition: tpl_arrayStack.H:385
Node * rotate_to_left(Node *p) noexcept
Definition: tpl_binNodeUtils.H:1932
Definition: tpl_rb_tree.H:503
virtual ~Gen_Rb_Tree()
Destruye un árbol rojo-negro.
Definition: tpl_rb_tree.H:344
Node * search(const Key &key)
Definition: tpl_rb_tree.H:349
Node * insert(Node *p)
Definition: tpl_rb_tree.H:361
Node *& RLINK(Node *p) noexcept
Definition: tpl_binNode.H:307

Leandro Rabindranath León