CCTLib
Calling-context and data-object attribution library for Intel Pin
rbtree.h
Go to the documentation of this file.
1 //
2 // main.cpp
3 // AugmentedRBTree
4 //
5 // Created by Milind Chabbi on 5/26/18.
6 // Copyright © 2018 Milind Chabbi. All rights reserved.
7 //
8 
9 #include <iostream>
10 #include <stdint.h>
11 
12 
13 enum COLOR { BLACK = 0,
14  RED = 1 };
15 
16 template <class K, class V, class S>
17 struct TreeNode {
22  K key;
23  V value;
24  S sum;
25  uint32_t payload;
26  TreeNode(K k, V v)
27  : key(k), value(v), payload(0) {}
28 };
29 
30 template <class K, class V, class S>
31 class RBTree {
33 
34  private:
36 
37  public:
39  : root(nullptr) {
40  }
41 
42  TNKV* InsertBST(TNKV* newNode) {
43  V inc = newNode->value;
44  newNode->left = newNode->right = newNode->parent = nullptr;
45  // always begin with a red color node
46  newNode->color = RED;
47  newNode->sum = inc;
48 
49  if (root == nullptr) {
50  root = newNode;
51  return newNode;
52  }
53 
54  TNKV* cur = root;
55  TNKV* parent = nullptr;
56 
57  while (cur) {
58  parent = cur;
59  parent->sum += inc;
60  if (newNode->key <= cur->key) {
61  cur = cur->left;
62  } else if (newNode->key > parent->key) {
63  cur = cur->right;
64  }
65  }
66 
67  if (newNode->key < parent->key) {
68  assert(parent->left == nullptr);
69  parent->left = newNode;
70  } else {
71  assert(parent->right == nullptr);
72  parent->right = newNode;
73  }
74  newNode->parent = parent;
75  return newNode;
76  }
77 
78  TNKV* FindSumGreaterEqual(K key, S* sum) {
79  *sum = 0;
80  if (root == nullptr) {
81  return nullptr;
82  }
83 
84  TNKV* cur = root;
85 
86  while (cur) {
87  if (key < cur->key) {
88  *sum += cur->value + (cur->right ? cur->right->sum : 0);
89  cur = cur->left;
90  } else if (key > cur->key) {
91  cur = cur->right;
92  } else {
93  *sum += cur->value + (cur->right ? cur->right->sum : 0);
94  break;
95  }
96  }
97  // if cur is null we found none
98  return cur;
99  }
100 
101  TNKV* FindSumGreaterThan(K key, S* sum) {
102  *sum = 0;
103  if (root == nullptr) {
104  return nullptr;
105  }
106 
107  TNKV* cur = root;
108 
109  while (cur) {
110  if (key < cur->key) {
111  *sum += cur->value + (cur->right ? cur->right->sum : 0);
112  cur = cur->left;
113  } else if (key > cur->key) {
114  cur = cur->right;
115  } else {
116  *sum += (cur->right ? cur->right->sum : 0);
117  break;
118  }
119  }
120  // if cur is null we found none
121  return cur;
122  }
123 
124  void UpdateSum(TNKV* node) {
125  node->sum = node->value + (node->left ? node->left->sum : 0) + (node->right ? node->right->sum : 0);
126  }
127 
128  COLOR GetColor(TNKV* const node) {
129  if (node) {
130  return node->color;
131  }
132  return BLACK;
133  }
134 
135  void SetColor(TNKV* node, COLOR color) {
136  if (node) {
137  node->color = color;
138  }
139  }
140 
142  assert(node);
143  return node->color;
144  }
145 
146  void SetColorUnconditional(TNKV* node, COLOR color) {
147  assert(node);
148  node->color = color;
149  }
150 
151 
152  // https://www.geeksforgeeks.org/c-program-red-black-tree-insertion/
153  // https://www.youtube.com/watch?v=6QOKk_pcv3U
154  /* . ==> red node
155  g p
156  / \ / \
157  u p. g. x.
158  / \ / \ ==> / \ / \
159  T1 T2 T3 x. u T3 T4 T5
160  /\ /\
161  T4 T5 T1 T2
162  */
163 
164 
165  // We get a pointer to the right child, which will be rotated anticlockwise around its parent.
166  void RotateLeft(TNKV* p) {
167  assert(p->parent);
168  // is it really needed?
169  //assert(p->parent->right);
170  assert(p->parent->right == p);
171  auto g = p->parent;
172  //auto u = g->right;
173  auto ggp = g->parent;
174 
175  p->parent = g->parent;
176  g->parent = p;
177  g->right = p->left;
178  if (p->left) {
179  p->left->parent = g;
180  }
181  p->left = g;
182 
183  if (ggp) {
184  if (ggp->left == g)
185  ggp->left = p;
186  else
187  ggp->right = p;
188  } else {
189  root = p;
190  }
191  // Adjust the sum
192  // u is unchanged
193  // x is unchanged
194  UpdateSum(g);
195  UpdateSum(p);
196  }
197 
198  /* . ==> red node
199  g x
200  / \ / \
201  u p. g. p.
202  / \ / \ ==> / \ / \
203  T1 T2 x. T5 u T3 T4 T5
204  /\ /\
205  T3 T4 T1 T2
206 */
207 
208 
209  // We get a pointer to x. It will be rotaed clockwise around its parent and then anticlockwise around the new parent.
211  assert(x->parent);
212  // is it really needed?
213  assert(x->parent->parent);
214  assert(x->parent->left == x);
215  assert(x->parent->parent->right == x->parent);
216  auto g = x->parent->parent;
217  auto p = x->parent;
218  auto ggp = g->parent;
219 
220  g->right = x->left;
221  if (x->left) {
222  x->left->parent = g;
223  }
224  p->left = x->right;
225  if (x->right) {
226  x->right->parent = p;
227  }
228  p->parent = x;
229  g->parent = x;
230  x->right = p;
231  x->left = g;
232  x->parent = ggp;
233  if (ggp) {
234  if (ggp->left == g)
235  ggp->left = x;
236  else
237  ggp->right = x;
238  } else {
239  root = x;
240  }
241 
242  // Adjust the sum
243  // u is unchanged
244  UpdateSum(p);
245  UpdateSum(g);
246  UpdateSum(x);
247  }
248 
249 
250  /*
251  g p
252  / \ / \
253  p. u x. g.
254  / \ / \ ==> / \ / \
255  x. T3 T4 T5 T1 T2 T3 u
256  /\ /\
257  T1 T2 T4 T5
258 
259  */
260 
261  // We get pointer to the left child.
262  // We rotate the node clockwise wrt to its parent.
263  void RotateRight(TNKV* p) {
264  assert(p->parent);
265  // is it really needed?
266  // assert(p->parent->right);
267  assert(p->parent->left == p);
268  auto g = p->parent;
269  //auto u = g->right;
270  auto ggp = g->parent;
271  p->parent = g->parent;
272  g->parent = p;
273  g->left = p->right;
274  if (p->right) {
275  p->right->parent = g;
276  }
277  p->right = g;
278 
279  if (ggp) {
280  if (ggp->left == g)
281  ggp->left = p;
282  else
283  ggp->right = p;
284  } else {
285  root = p;
286  }
287 
288  // Adjust the sum
289  // u is unchanged
290  // x is unchanged
291  UpdateSum(g);
292  UpdateSum(p);
293  }
294 
295  /*
296  g x
297  / \ / \
298  p. u p. g.
299  / \ / \ ==> / \ / \
300  T1 x. T4 T5 T1 T2 T3 u
301  /\ /\
302  T2 T3 T4 T5
303 
304  */
305 
306  // x is the right child.
307  // Effectively, we rotate x anticlockwise around its parent and then clockwise around the new parent.
309  assert(x->parent);
310  // is it really needed?
311  assert(x->parent->parent);
312  assert(x->parent->right == x);
313  assert(x->parent->parent->left == x->parent);
314  auto g = x->parent->parent;
315  auto p = x->parent;
316  auto ggp = g->parent;
317 
318  g->left = x->right;
319  if (x->right) {
320  x->right->parent = g;
321  }
322  p->right = x->left;
323  if (x->left) {
324  x->left->parent = p;
325  }
326  p->parent = x;
327  g->parent = x;
328  x->left = p;
329  x->right = g;
330  x->parent = ggp;
331  if (ggp) {
332  if (ggp->left == g)
333  ggp->left = x;
334  else
335  ggp->right = x;
336  } else {
337  root = x;
338  }
339  // Adjust the sum
340  // u is unchanged
341  UpdateSum(p);
342  UpdateSum(g);
343  UpdateSum(x);
344  }
345 
347  if (!x->parent) {
348  // reached root, color it black
349  x->color = BLACK;
350  return;
351  }
352  // Do we have a double red problem?
353  if (x->parent->color == BLACK) {
354  return; // no problem
355  }
356 
357  // since parent is red, there must be grand parent
358  auto p = x->parent;
359  auto g = x->parent->parent;
360  // is p left of g -- g is non-null by RB invariant (a red parent is
361  // never the root, so the grandparent always exists), see comment above.
362  if (p == g->left) { // NOLINT(clang-analyzer-core.NullDereference)
363  // is uncle red? if so, recolor
364  auto u = g->right;
365  if (u && (u->color == RED)) {
369  // x will remain red.
371  } else {
372  // is x left of p?
373  if (p->left == x) {
374  RotateRight(p);
375  //Recolor
376  // x = g = red.
377  // p = black
381  // end of protocol on a rotation
382  } else {
383  assert(p->right == x);
388  // end of protocol on a rotation
389  }
390  }
391  } else {
392  // p is right child of g
393  assert(p == g->right);
394 
395  // is uncle red? if so, recolor
396  auto u = g->left;
397  if (u && (u->color == RED)) {
401  // x will remain red.
403  } else {
404  // is x right of p?
405  if (p->right == x) {
406  RotateLeft(p);
408  SetColorUnconditional(g /*now the new sibling */, RED);
409  SetColorUnconditional(p /*now the new sibling */, BLACK);
410  // end of protocol on a rotation
411  } else {
412  assert(p->left == x);
414  //Recolor
415  // p = g = red.
416  // x = black
420  // end of protocol on a rotation
421  }
422  }
423  }
424  }
425 
426  void Insert(TNKV* newNode) {
427  InsertBST(newNode);
428  BalanceInsertion(newNode);
429  }
430 
431  void BalanceDeletion(TNKV* node) {
432  // Deleting a red node is harmless (does not change the black depth).
433  if (node->color == RED) {
434  return;
435  }
436 
437  // Node is BLACK. If it has at least one RED child, recoloring the child with BLACK will fix the height problem.
438  // TODO: it can only have the right child.
439  if (GetColor(node->left) == RED || GetColor(node->right) == RED) {
440  TNKV* child = node->left != nullptr ? node->left : node->right;
442  return;
443  }
444 
445  // Series of harder cases where node is black and it has no red children.
446 
447  TNKV* sibling = nullptr;
448  TNKV* parent = nullptr;
449  TNKV* ptr = node;
450  while (ptr != root) {
451  parent = ptr->parent;
452  if (ptr == parent->left) {
453  // Left subtree shrank in height
454  sibling = parent->right;
455  if (GetColor(sibling) == RED) {
456  SetColor(sibling, BLACK);
457  SetColor(parent, RED);
458  RotateLeft(sibling);
459  } else {
460  if ((!sibling) ||
461  (GetColor(sibling->left) == BLACK && GetColor(sibling->right) == BLACK)) {
462  if (sibling) {
463  SetColorUnconditional(sibling, RED);
464  }
465 
466  if (GetColorUnconditional(parent) == RED) {
467  SetColorUnconditional(parent, BLACK);
468  } else {
469  SetColorUnconditional(parent, BLACK);
470  ptr = parent;
471  continue;
472  }
473  } else {
474  if (GetColor(sibling->right) == BLACK) {
475  SetColorUnconditional(sibling->left, parent->color);
476  SetColorUnconditional(parent, BLACK);
477  RotateRightThenLeft(sibling->left);
478  } else {
479  SetColorUnconditional(sibling, parent->color);
480  SetColorUnconditional(parent, BLACK);
481  SetColorUnconditional(sibling->right, BLACK);
482  RotateLeft(sibling);
483  }
484  }
485  }
486  } else {
487  // Right subtree shrank in height
488  sibling = parent->left;
489  if (GetColor(sibling) == RED) {
490  SetColor(sibling, BLACK);
491  SetColor(parent, RED);
492  RotateRight(sibling);
493  } else {
494  if ((!sibling) ||
495  (GetColor(sibling->left) == BLACK && GetColor(sibling->right) == BLACK)) {
496  if (sibling) {
497  SetColorUnconditional(sibling, RED);
498  }
499 
500  if (GetColorUnconditional(parent) == RED) {
501  SetColorUnconditional(parent, BLACK);
502  } else {
503  SetColorUnconditional(parent, BLACK);
504  ptr = parent;
505  continue;
506  }
507  } else {
508  if (GetColor(sibling->left) == BLACK) {
509  SetColorUnconditional(sibling->right, parent->color);
510  SetColorUnconditional(parent, BLACK);
511  RotateLeftThenRight(sibling->right);
512  } else {
513  SetColorUnconditional(sibling, parent->color);
514  SetColorUnconditional(parent, BLACK);
515  SetColorUnconditional(sibling->left, BLACK);
516  RotateRight(sibling);
517  }
518  }
519  }
520  }
521  break;
522  }
524  }
525 
527  // Case 1: no children
528  if (node->left == nullptr && node->right == nullptr) {
529  if (node == root) {
530  root = nullptr;
531  } else {
532  TNKV** whomToUpdate = (node->parent->left == node) ? (&node->parent->left) : (&node->parent->right);
533  *whomToUpdate = nullptr;
534  }
535  return node;
536  }
537  // Case 2: single child
538  if (node->left == nullptr || node->right == nullptr) {
539  TNKV* parent = node->parent;
540 
541  TNKV* theChild = (node->left) ? (node->left) : (node->right);
542  if (parent) {
543  TNKV** theParentLoc = (parent->left == node) ? (&parent->left) : (&parent->right);
544  *theParentLoc = theChild;
545  } else {
546  root = theChild;
547  }
548  theChild->parent = parent;
549  return node;
550  }
551  // Case 3: both children
552 
553  // Get the in-order successor
554 
555  TNKV* curParent = nullptr;
556  for (TNKV* cur = node->right; cur != nullptr; cur = cur->left) {
557  curParent = cur;
558  }
559 
560  V dec = curParent->value;
561  // Update the sum since this subtree lost a node
562  for (TNKV* cur = curParent->parent; cur != node; cur = cur->parent) {
563  cur->sum -= dec;
564  }
565 
566  // swap curParent with node
567  auto tmp1 = node->key;
568  node->key = curParent->key;
569  curParent->key = tmp1;
570 
571  auto tmp2 = node->value;
572  node->value = curParent->value;
573  curParent->value = tmp2;
574 
575  auto tmp3 = node->payload;
576  node->payload = curParent->payload;
577  curParent->payload = tmp3;
578 
579  // Now, delete curParent
580  return DeleteHelper(curParent);
581  }
582 
584  // Case 1: no or single single child
585  if (node->left == nullptr || node->right == nullptr) {
586  node->sum = 0;
587  if (node->left != nullptr) {
588  node->sum += node->left->sum;
589  }
590  if (node->right != nullptr) {
591  node->sum += node->right->sum;
592  }
593  return node;
594  }
595  // Get the in-order successor
596 
597  TNKV* curParent = nullptr;
598  for (TNKV* cur = node->right; cur != nullptr; cur = cur->left) {
599  curParent = cur;
600  }
601 
602  V dec = curParent->value;
603  // Update the sum since this subtree lost a node
604  for (TNKV* cur = curParent->parent; cur != node; cur = cur->parent) {
605  cur->sum -= dec;
606  }
607 
608  // swap curParent with node
609  auto tmp1 = node->key;
610  node->key = curParent->key;
611  curParent->key = tmp1;
612 
613  auto tmp2 = node->value;
614  node->value = curParent->value;
615  curParent->value = tmp2;
616 
617  auto tmp3 = node->payload;
618  node->payload = curParent->payload;
619  curParent->payload = tmp3;
620 
621  // Now, delete curParent
622  return WhichNodeToDelete(curParent);
623  }
624 
625  TNKV* Delete(TNKV* node) {
626  V dec = node->value;
627  // decrement this value from parents
628  for (TNKV* cur = node; cur; cur = cur->parent) {
629  cur->sum -= dec;
630  }
631  // auto delNode = DeleteHelper(node);
632  auto delNode = WhichNodeToDelete(node);
633  BalanceDeletion(delNode);
634  assert(delNode->left == nullptr || (delNode->right == nullptr));
635  if (delNode->parent) {
636  if (delNode->parent->left == delNode) {
637  if (delNode->right) {
638  delNode->parent->left = delNode->right;
639  delNode->right->parent = delNode->parent;
640  } else if (delNode->left) {
641  delNode->parent->left = delNode->left;
642  delNode->left->parent = delNode->parent;
643  } else {
644  delNode->parent->left = nullptr;
645  }
646  } else {
647  if (delNode->right) {
648  delNode->parent->right = delNode->right;
649  delNode->right->parent = delNode->parent;
650  } else if (delNode->left) {
651  delNode->parent->right = delNode->left;
652  delNode->left->parent = delNode->parent;
653  } else {
654  delNode->parent->right = nullptr;
655  }
656  }
657  } else {
658  if (delNode->right) {
659  root = delNode->right;
660  delNode->right->parent = nullptr;
661  } else if (delNode->left) {
662  root = delNode->left;
663  delNode->left->parent = nullptr;
664  } else {
665  root = nullptr;
666  }
667  }
668  return delNode;
669  }
670 
671  bool IsBSTHelper(TNKV* node) {
672  if (!node)
673  return true;
674 
675  if (node->left) {
676  if (node->left->key > node->key)
677  return false;
678  }
679 
680  if (node->right) {
681  if (node->right->key <= node->key)
682  return false;
683  }
684 
685  return IsBSTHelper(node->left) && IsBSTHelper(node->right);
686  }
687 
688  bool IsBST() {
689  if (!root)
690  return true;
691 
692  return IsBSTHelper(root);
693  }
694 
695  bool IsSumCorrectHeler(TNKV* node, V& curSum) {
696  if (node == nullptr) {
697  curSum = 0;
698  return true;
699  }
700 
701  V lSum = node->left ? node->left->sum : 0;
702  V rSum = node->right ? node->right->sum : 0;
703  if ((lSum + rSum + node->value) != node->sum) {
704  return false;
705  }
706 
707  if (!IsSumCorrectHeler(node->left, lSum))
708  return false;
709  if (!IsSumCorrectHeler(node->right, rSum))
710  return false;
711 
712  if ((lSum + rSum + node->value) != node->sum) {
713  return false;
714  }
715  curSum = lSum + rSum + node->value;
716  return true;
717  }
718 
719  bool IsSumCorrect() {
720  V curSum;
721  if (!root)
722  return true;
723 
724  return IsSumCorrectHeler(root, curSum);
725  }
726 
727  bool IsTreeCorrectHeler(TNKV* node) {
728  if (node == nullptr) {
729  return true;
730  }
731 
732  if (node->left) {
733  if (node->left->parent != node)
734  return false;
735  }
736 
737  if (node->right) {
738  if (node->right->parent != node)
739  return false;
740  }
741 
742  if (node->color == RED && (!node->parent || node->parent->color == RED)) {
743  return false;
744  }
745 
746  return IsTreeCorrectHeler(node->left) && IsTreeCorrectHeler(node->right);
747  }
748 
749 
750  bool IsTreeCorrect() {
751  if (!root)
752  return true;
753 
754  return IsTreeCorrectHeler(root);
755  }
756 
757  bool IsReachableHelper(TNKV* root, TNKV* target) {
758  if (!root) {
759  return false;
760  }
761 
762  if (root == target)
763  return true;
764  auto l = IsReachableHelper(root->left, target);
765  auto r = IsReachableHelper(root->right, target);
766  if (l && !r)
767  return true;
768  if (!l && r)
769  return true;
770  return false;
771  }
772 
773  bool IsReachable(TNKV* target) {
774  return IsReachableHelper(root, target);
775  }
776 
778  return root ? root->sum : 0;
779  }
780 
781  // Find the eviction victim for a fully-associative LRU cache of the
782  // given capacity (measured in sum of node values from the MRU end).
783  // Returns the node whose cumulative rank from the rightmost (MRU) end
784  // first exceeds capacity, i.e. the node at the cache boundary.
785  // Returns nullptr if the entire working set fits (total sum <= capacity).
787  if (!root || root->sum <= capacity)
788  return nullptr;
789  TNKV* cur = root;
790  S remaining = capacity;
791  while (cur) {
792  S rightSum = cur->right ? cur->right->sum : 0;
793  if (remaining < rightSum) {
794  cur = cur->right;
795  } else if (remaining < rightSum + (S)cur->value) {
796  return cur;
797  } else {
798  remaining -= rightSum + (S)cur->value;
799  cur = cur->left;
800  }
801  }
802  return nullptr;
803  }
804 };
805 
806 #if RBTREE_TEST
807 #define N (1L << 12)
808 
809 void Test1() {
811 
812  uint32_t* k = new uint32_t[N];
813  uint32_t* v = new uint32_t[N];
815 
816  for (int i = 0; i < N; i++) {
817  k[i] = uint32_t(rand());
818  v[i] = uint32_t(rand());
819  }
820 
821  for (int i = 0; i < N; i++) {
823  //t->key = k[i];
824  //t->value = v[i];
825  tn[i] = t;
826  rbt.Insert(t);
827  assert(rbt.IsBST());
828  assert(rbt.IsSumCorrect());
829  assert(rbt.IsTreeCorrect());
830 
831  volatile int pp = 1;
832  if (pp && (i > 0) && (i % 100 == 0)) {
833  int j = uint32_t(rand()) % i;
834  auto d = rbt.Delete(tn[j]);
835  assert(rbt.IsBST());
836  assert(rbt.IsSumCorrect());
837  assert(rbt.IsTreeCorrect());
838  rbt.Insert(d);
839  assert(rbt.IsBST());
840  assert(rbt.IsSumCorrect());
841  assert(rbt.IsTreeCorrect());
842  }
843  }
844 
845  for (int i = 0; i < N; i++) {
846  int j = i; //uint32_t(rand()) % N;
847  if (tn[j]) {
848  auto nn = rbt.Delete(tn[j]);
849  for (int k = 0; k < N; k++) {
850  if (tn[k] == nn) {
851  tn[k] = 0;
852  break;
853  }
854  }
855  }
856  for (int k = 0; k < N; k++) {
857  if (tn[k]) {
858  assert(rbt.IsReachable(tn[k]));
859  }
860  }
861  assert(rbt.IsBST());
862  assert(rbt.IsSumCorrect());
863  assert(rbt.IsTreeCorrect());
864  }
865 }
866 
867 int main(int argc, const char* argv[]) {
868  // insert code here...
869  std::cout << "Hello, World!\n";
870  Test1();
871  std::cout << "Great, World!\n";
872  return 0;
873 }
874 #endif // RBTREE_TEST
int main(int argc, char *argv[])
Definition: rbtree.h:31
TNKV * DeleteHelper(TNKV *node)
Definition: rbtree.h:526
TNKV * FindSumGreaterThan(K key, S *sum)
Definition: rbtree.h:101
bool IsReachable(TNKV *target)
Definition: rbtree.h:773
TNKV * WhichNodeToDelete(TNKV *node)
Definition: rbtree.h:583
void Insert(TNKV *newNode)
Definition: rbtree.h:426
void BalanceDeletion(TNKV *node)
Definition: rbtree.h:431
bool IsTreeCorrectHeler(TNKV *node)
Definition: rbtree.h:727
bool IsBST()
Definition: rbtree.h:688
void RotateLeftThenRight(TNKV *x)
Definition: rbtree.h:308
S GetTotalSum()
Definition: rbtree.h:777
void RotateRightThenLeft(TNKV *x)
Definition: rbtree.h:210
RBTree()
Definition: rbtree.h:38
void UpdateSum(TNKV *node)
Definition: rbtree.h:124
TNKV * Delete(TNKV *node)
Definition: rbtree.h:625
bool IsReachableHelper(TNKV *root, TNKV *target)
Definition: rbtree.h:757
TNKV * FindNodeAtRankFromRight(S capacity)
Definition: rbtree.h:786
bool IsTreeCorrect()
Definition: rbtree.h:750
COLOR GetColorUnconditional(TNKV *const node)
Definition: rbtree.h:141
void SetColorUnconditional(TNKV *node, COLOR color)
Definition: rbtree.h:146
bool IsBSTHelper(TNKV *node)
Definition: rbtree.h:671
bool IsSumCorrectHeler(TNKV *node, V &curSum)
Definition: rbtree.h:695
TreeNode< K, V, S > * root
Definition: rbtree.h:35
void BalanceInsertion(TNKV *x)
Definition: rbtree.h:346
bool IsSumCorrect()
Definition: rbtree.h:719
TNKV * FindSumGreaterEqual(K key, S *sum)
Definition: rbtree.h:78
TNKV * InsertBST(TNKV *newNode)
Definition: rbtree.h:42
void RotateLeft(TNKV *p)
Definition: rbtree.h:166
void SetColor(TNKV *node, COLOR color)
Definition: rbtree.h:135
void RotateRight(TNKV *p)
Definition: rbtree.h:263
COLOR GetColor(TNKV *const node)
Definition: rbtree.h:128
COLOR
Definition: rbtree.h:13
@ BLACK
Definition: rbtree.h:13
@ RED
Definition: rbtree.h:14
COLOR color
Definition: rbtree.h:21
TreeNode(K k, V v)
Definition: rbtree.h:26
K key
Definition: rbtree.h:22
TreeNode * right
Definition: rbtree.h:19
S sum
Definition: rbtree.h:24
V value
Definition: rbtree.h:23
uint32_t payload
Definition: rbtree.h:25
TreeNode * left
Definition: rbtree.h:18
TreeNode * parent
Definition: rbtree.h:20
#define N
Definition: test1.c:2
void g()
Definition: test1.c:6