source: rtems/cpukit/score/src/rbtreeextract.c @ 2369b10

4.115
Last change on this file since 2369b10 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

  • Property mode set to 100644
File size: 7.1 KB
Line 
1/*
2 *  Copyright (c) 2010 Gedare Bloom.
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.org/license/LICENSE.
7 */
8
9#if HAVE_CONFIG_H
10#include "config.h"
11#endif
12
13#include <rtems/score/rbtreeimpl.h>
14#include <rtems/score/isr.h>
15
16/** @brief  Validate and fix-up tree properties after deleting a node
17 *
18 *  This routine is called on a black node, @a the_node, after its deletion.
19 *  This function maintains the properties of the red-black tree.
20 *
21 *  @note It does NOT disable interrupts to ensure the atomicity
22 *        of the extract operation.
23 */
24static void _RBTree_Extract_validate(
25    RBTree_Node *the_node
26    )
27{
28  RBTree_Node *parent, *sibling;
29  RBTree_Direction dir;
30
31  parent = the_node->parent;
32  if(!parent->parent) return;
33
34  sibling = _RBTree_Sibling(the_node);
35
36  /* continue to correct tree as long as the_node is black and not the root */
37  while (!_RBTree_Is_red(the_node) && parent->parent) {
38
39    /* if sibling is red, switch parent (black) and sibling colors,
40     * then rotate parent left, making the sibling be the_node's grandparent.
41     * Now the_node has a black sibling and red parent. After rotation,
42     * update sibling pointer.
43     */
44    if (_RBTree_Is_red(sibling)) {
45      parent->color = RBT_RED;
46      sibling->color = RBT_BLACK;
47      dir = the_node != parent->child[0];
48      _RBTree_Rotate(parent, dir);
49      sibling = parent->child[_RBTree_Opposite_direction(dir)];
50    }
51
52    /* sibling is black, see if both of its children are also black. */
53    if (!_RBTree_Is_red(sibling->child[RBT_RIGHT]) &&
54        !_RBTree_Is_red(sibling->child[RBT_LEFT])) {
55        sibling->color = RBT_RED;
56        if (_RBTree_Is_red(parent)) {
57          parent->color = RBT_BLACK;
58          break;
59        }
60        the_node = parent; /* done if parent is red */
61        parent = the_node->parent;
62        sibling = _RBTree_Sibling(the_node);
63    } else {
64      /* at least one of sibling's children is red. we now proceed in two
65       * cases, either the_node is to the left or the right of the parent.
66       * In both cases, first check if one of sibling's children is black,
67       * and if so rotate in the proper direction and update sibling pointer.
68       * Then switch the sibling and parent colors, and rotate through parent.
69       */
70      dir = the_node != parent->child[0];
71      if (!_RBTree_Is_red(sibling->child[_RBTree_Opposite_direction(dir)])) {
72        sibling->color = RBT_RED;
73        sibling->child[dir]->color = RBT_BLACK;
74        _RBTree_Rotate(sibling, _RBTree_Opposite_direction(dir));
75        sibling = parent->child[_RBTree_Opposite_direction(dir)];
76      }
77      sibling->color = parent->color;
78      parent->color = RBT_BLACK;
79      sibling->child[_RBTree_Opposite_direction(dir)]->color = RBT_BLACK;
80      _RBTree_Rotate(parent, dir);
81      break; /* done */
82    }
83  } /* while */
84  if(!the_node->parent->parent) the_node->color = RBT_BLACK;
85}
86
87/** @brief Extract a Node (unprotected)
88 *
89 *  This routine extracts (removes) @a the_node from @a the_rbtree.
90 *
91 *  @note It does NOT disable interrupts to ensure the atomicity
92 *        of the extract operation.
93 */
94void _RBTree_Extract(
95    RBTree_Control *the_rbtree,
96    RBTree_Node *the_node
97    )
98{
99  RBTree_Node *leaf, *target;
100  RBTree_Color victim_color;
101  RBTree_Direction dir;
102
103  if (!the_node) return;
104
105  /* check if min needs to be updated */
106  if (the_node == the_rbtree->first[RBT_LEFT]) {
107    RBTree_Node *next;
108    next = _RBTree_Successor(the_node);
109    the_rbtree->first[RBT_LEFT] = next;
110  }
111
112  /* Check if max needs to be updated. min=max for 1 element trees so
113   * do not use else if here. */
114  if (the_node == the_rbtree->first[RBT_RIGHT]) {
115    RBTree_Node *previous;
116    previous = _RBTree_Predecessor(the_node);
117    the_rbtree->first[RBT_RIGHT] = previous;
118  }
119
120  /* if the_node has at most one non-null child then it is safe to proceed
121   * check if both children are non-null, if so then we must find a target node
122   * either max in node->child[RBT_LEFT] or min in node->child[RBT_RIGHT],
123   * and replace the_node with the target node. This maintains the binary
124   * search tree property, but may violate the red-black properties.
125   */
126
127  if (the_node->child[RBT_LEFT] && the_node->child[RBT_RIGHT]) {
128    target = the_node->child[RBT_LEFT]; /* find max in node->child[RBT_LEFT] */
129    while (target->child[RBT_RIGHT]) target = target->child[RBT_RIGHT];
130
131    /* if the target node has a child, need to move it up the tree into
132     * target's position (target is the right child of target->parent)
133     * when target vacates it. if there is no child, then target->parent
134     * should become NULL. This may cause the coloring to be violated.
135     * For now we store the color of the node being deleted in victim_color.
136     */
137    leaf = target->child[RBT_LEFT];
138    if(leaf) {
139      leaf->parent = target->parent;
140    } else {
141      /* fix the tree here if the child is a null leaf. */
142      _RBTree_Extract_validate(target);
143    }
144    victim_color = target->color;
145    dir = target != target->parent->child[0];
146    target->parent->child[dir] = leaf;
147
148    /* now replace the_node with target */
149    dir = the_node != the_node->parent->child[0];
150    the_node->parent->child[dir] = target;
151
152    /* set target's new children to the original node's children */
153    target->child[RBT_RIGHT] = the_node->child[RBT_RIGHT];
154    if (the_node->child[RBT_RIGHT])
155      the_node->child[RBT_RIGHT]->parent = target;
156    target->child[RBT_LEFT] = the_node->child[RBT_LEFT];
157    if (the_node->child[RBT_LEFT])
158      the_node->child[RBT_LEFT]->parent = target;
159
160    /* finally, update the parent node and recolor. target has completely
161     * replaced the_node, and target's child has moved up the tree if needed.
162     * the_node is no longer part of the tree, although it has valid pointers
163     * still.
164     */
165    target->parent = the_node->parent;
166    target->color = the_node->color;
167  } else {
168    /* the_node has at most 1 non-null child. Move the child in to
169     * the_node's location in the tree. This may cause the coloring to be
170     * violated. We will fix it later.
171     * For now we store the color of the node being deleted in victim_color.
172     */
173    leaf = the_node->child[RBT_LEFT] ?
174              the_node->child[RBT_LEFT] : the_node->child[RBT_RIGHT];
175    if( leaf ) {
176      leaf->parent = the_node->parent;
177    } else {
178      /* fix the tree here if the child is a null leaf. */
179      _RBTree_Extract_validate(the_node);
180    }
181    victim_color = the_node->color;
182
183    /* remove the_node from the tree */
184    dir = the_node != the_node->parent->child[0];
185    the_node->parent->child[dir] = leaf;
186  }
187
188  /* fix coloring. leaf has moved up the tree. The color of the deleted
189   * node is in victim_color. There are two cases:
190   *   1. Deleted a red node, its child must be black. Nothing must be done.
191   *   2. Deleted a black node, its child must be red. Paint child black.
192   */
193  if (victim_color == RBT_BLACK) { /* eliminate case 1 */
194    if (leaf) {
195      leaf->color = RBT_BLACK; /* case 2 */
196    }
197  }
198
199  /* Wipe the_node */
200  _RBTree_Set_off_rbtree(the_node);
201
202  /* set root to black, if it exists */
203  if (the_rbtree->root) the_rbtree->root->color = RBT_BLACK;
204}
Note: See TracBrowser for help on using the repository browser.