source: rtems/cpukit/score/src/rbtreeextract.c @ 54cf0e34

4.115
Last change on this file since 54cf0e34 was 0ef6e3bf, checked in by Sebastian Huber <sebastian.huber@…>, on 07/24/14 at 15:50:58

rbtree: Simplify _RBTree_Extract()

  • Property mode set to 100644
File size: 7.0 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
15/** @brief  Validate and fix-up tree properties after deleting a node
16 *
17 *  This routine is called on a black node, @a the_node, after its deletion.
18 *  This function maintains the properties of the red-black tree.
19 *
20 *  @note It does NOT disable interrupts to ensure the atomicity
21 *        of the extract operation.
22 */
23static void _RBTree_Extract_validate( RBTree_Node *the_node )
24{
25  RBTree_Node     *parent;
26
27  parent = the_node->parent;
28
29  if ( !parent->parent )
30    return;
31
32  /* continue to correct tree as long as the_node is black and not the root */
33  while ( !_RBTree_Is_red( the_node ) && parent->parent ) {
34    RBTree_Node *sibling = _RBTree_Sibling( the_node, parent );
35
36    /* if sibling is red, switch parent (black) and sibling colors,
37     * then rotate parent left, making the sibling be the_node's grandparent.
38     * Now the_node has a black sibling and red parent. After rotation,
39     * update sibling pointer.
40     */
41    if ( _RBTree_Is_red( sibling ) ) {
42      RBTree_Direction dir = _RBTree_Direction( the_node, parent );
43      RBTree_Direction opp_dir = _RBTree_Opposite_direction( dir );
44
45      parent->color = RBT_RED;
46      sibling->color = RBT_BLACK;
47      _RBTree_Rotate( parent, dir );
48      sibling = parent->child[ opp_dir ];
49    }
50
51    /* sibling is black, see if both of its children are also black. */
52    if ( !_RBTree_Is_red( sibling->child[ RBT_RIGHT ] ) &&
53         !_RBTree_Is_red( sibling->child[ RBT_LEFT ] ) ) {
54      sibling->color = RBT_RED;
55
56      if ( _RBTree_Is_red( parent ) ) {
57        parent->color = RBT_BLACK;
58        break;
59      }
60
61      the_node = parent;   /* done if parent is red */
62      parent = the_node->parent;
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      RBTree_Direction dir = _RBTree_Direction( the_node, parent );
71      RBTree_Direction opp_dir = _RBTree_Opposite_direction( dir );
72
73      if (
74        !_RBTree_Is_red( sibling->child[ opp_dir ] )
75      ) {
76        sibling->color = RBT_RED;
77        sibling->child[ dir ]->color = RBT_BLACK;
78        _RBTree_Rotate( sibling, opp_dir );
79        sibling = parent->child[ opp_dir ];
80      }
81
82      sibling->color = parent->color;
83      parent->color = RBT_BLACK;
84      sibling->child[ opp_dir ]->color = RBT_BLACK;
85      _RBTree_Rotate( parent, dir );
86      break; /* done */
87    }
88  } /* while */
89
90  if ( !the_node->parent->parent )
91    the_node->color = RBT_BLACK;
92}
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  /* check if min needs to be updated */
104  if ( the_node == the_rbtree->first[ RBT_LEFT ] ) {
105    RBTree_Node *next;
106    next = _RBTree_Successor( the_node );
107    the_rbtree->first[ RBT_LEFT ] = next;
108  }
109
110  /* Check if max needs to be updated. min=max for 1 element trees so
111   * do not use else if here. */
112  if ( the_node == the_rbtree->first[ RBT_RIGHT ] ) {
113    RBTree_Node *previous;
114    previous = _RBTree_Predecessor( the_node );
115    the_rbtree->first[ RBT_RIGHT ] = previous;
116  }
117
118  /* if the_node has at most one non-null child then it is safe to proceed
119   * check if both children are non-null, if so then we must find a target node
120   * either max in node->child[RBT_LEFT] or min in node->child[RBT_RIGHT],
121   * and replace the_node with the target node. This maintains the binary
122   * search tree property, but may violate the red-black properties.
123   */
124
125  if ( the_node->child[ RBT_LEFT ] && the_node->child[ RBT_RIGHT ] ) {
126    target = the_node->child[ RBT_LEFT ]; /* find max in node->child[RBT_LEFT] */
127
128    while ( target->child[ RBT_RIGHT ] )
129      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
139    if ( leaf ) {
140      leaf->parent = target->parent;
141    } else {
142      /* fix the tree here if the child is a null leaf. */
143      _RBTree_Extract_validate( target );
144    }
145
146    victim_color = target->color;
147    dir = target != target->parent->child[ 0 ];
148    target->parent->child[ dir ] = leaf;
149
150    /* now replace the_node with target */
151    dir = the_node != the_node->parent->child[ 0 ];
152    the_node->parent->child[ dir ] = target;
153
154    /* set target's new children to the original node's children */
155    target->child[ RBT_RIGHT ] = the_node->child[ RBT_RIGHT ];
156
157    if ( the_node->child[ RBT_RIGHT ] )
158      the_node->child[ RBT_RIGHT ]->parent = target;
159
160    target->child[ RBT_LEFT ] = the_node->child[ RBT_LEFT ];
161
162    if ( the_node->child[ RBT_LEFT ] )
163      the_node->child[ RBT_LEFT ]->parent = target;
164
165    /* finally, update the parent node and recolor. target has completely
166     * replaced the_node, and target's child has moved up the tree if needed.
167     * the_node is no longer part of the tree, although it has valid pointers
168     * still.
169     */
170    target->parent = the_node->parent;
171    target->color = the_node->color;
172  } else {
173    /* the_node has at most 1 non-null child. Move the child in to
174     * the_node's location in the tree. This may cause the coloring to be
175     * violated. We will fix it later.
176     * For now we store the color of the node being deleted in victim_color.
177     */
178    leaf = the_node->child[ RBT_LEFT ] ?
179           the_node->child[ RBT_LEFT ] : the_node->child[ RBT_RIGHT ];
180
181    if ( leaf ) {
182      leaf->parent = the_node->parent;
183    } else {
184      /* fix the tree here if the child is a null leaf. */
185      _RBTree_Extract_validate( the_node );
186    }
187
188    victim_color = the_node->color;
189
190    /* remove the_node from the tree */
191    dir = the_node != the_node->parent->child[ 0 ];
192    the_node->parent->child[ dir ] = leaf;
193  }
194
195  /* fix coloring. leaf has moved up the tree. The color of the deleted
196   * node is in victim_color. There are two cases:
197   *   1. Deleted a red node, its child must be black. Nothing must be done.
198   *   2. Deleted a black node, its child must be red. Paint child black.
199   */
200  if ( victim_color == RBT_BLACK ) { /* eliminate case 1 */
201    if ( leaf ) {
202      leaf->color = RBT_BLACK; /* case 2 */
203    }
204  }
205
206  /* set root to black, if it exists */
207  if ( the_rbtree->root )
208    the_rbtree->root->color = RBT_BLACK;
209}
Note: See TracBrowser for help on using the repository browser.