|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
redblack.c
Abstract: This module implements red/black trees. Author:
16-Jun-1995 t-orig
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "gen.h"
PKNOWNTYPES NIL;
#define RIGHT(x) x->RBRight
#define LEFT(x) x->RBLeft
#define PARENT(x) x->RBParent
#define COLOR(x) x->RBColor
#define KEY(x) x->TypeName
VOID RBInitTree( PRBTREE ptree ) { ptree->pRoot = NIL; ptree->pLastNodeInserted = NULL; }
PKNOWNTYPES RBLeftRotate( PKNOWNTYPES root, PKNOWNTYPES x ) /*++
Routine Description:
Rotates the tree to the left at node x.
x y / \ / \ A y ==>> x C / \ / \ B C A B
Arguments:
root - The root of the Red/Black tree x - The node at which to rotate
Return Value:
return-value - The new root of the tree (which could be the same as the old root).
--*/ { PKNOWNTYPES y;
y = RIGHT(x); RIGHT(x) = LEFT(y); if (LEFT(y) != NIL){ PARENT(LEFT(y)) = x; } PARENT(y) = PARENT(x); if (PARENT(x) == NIL){ root = y; } else if (x==LEFT(PARENT(x))) { LEFT(PARENT(x)) = y; } else { RIGHT(PARENT(x))= y; } LEFT(y) = x; PARENT(x) = y; return root; }
PKNOWNTYPES RBRightRotate( PKNOWNTYPES root, PKNOWNTYPES x ) /*++
Routine Description:
Rotates the tree to the right at node x.
x y / \ / \ y C ==>> A x / \ / \ A B B C
Arguments:
root - The root of the Red/Black tree x - The node at which to rotate
Return Value:
return-value - The new root of the tree (which could be the same as the old root).
--*/ { PKNOWNTYPES y;
y = LEFT(x); LEFT(x) = RIGHT(y); if (RIGHT(y) != NIL) { PARENT(RIGHT(y)) = x; } PARENT(y) = PARENT(x); if (PARENT(x) == NIL) { root = y; } else if (x==LEFT(PARENT(x))) { LEFT(PARENT(x)) = y; } else { RIGHT(PARENT(x))= y; } RIGHT(y) = x; PARENT(x) = y; return root; }
PKNOWNTYPES RBTreeInsert( PKNOWNTYPES root, PKNOWNTYPES z ) /*++
Routine Description:
Inserts a new node into a tree without preserving the red/black properties. Should ONLY be called by RBInsert! This is just a simple binary tree insertion routine.
Arguments:
root - The root of the red/black tree z - The new node to insert
Return Value:
return-value - The new root of the tree (which could be the same as the old root).
--*/ { PKNOWNTYPES x,y; int i;
y = NIL; x = root;
LEFT(z) = RIGHT(z) = NIL;
// Find a place to insert z by doing a simple binary search
while (x!=NIL) { y = x; i = strcmp(KEY(z), KEY(x)); if (i < 0){ x = LEFT(x); } else { x = RIGHT(x); } }
// Insert z into the tree
PARENT(z)= y;
if (y==NIL) { root = z; } else if (i<0) { LEFT(y) = z; } else { RIGHT(y) = z; }
return root; }
VOID RBInsert( PRBTREE ptree, PKNOWNTYPES x ) /*++
Routine Description:
Inserts a node into a red/black tree while preserving the red/black properties.
Arguments:
root - The root of the red/black tree z - The new node to insert
Return Value:
return-value - The new root of the tree (which could be the same as the old root).
--*/ { PKNOWNTYPES root = ptree->pRoot; PKNOWNTYPES y;
// Make a linked-list of nodes for easy deletion
x->Next = ptree->pLastNodeInserted; ptree->pLastNodeInserted = x; // Insert x into the tree without preserving the red/black properties
root = RBTreeInsert (root, x); COLOR(x) = RED;
// We can stop fixing the tree when either:
// 1) We got to the root
// 2) x has a BLACK parent (the tree obeys the red/black properties,
// because no RED parent has a RED child.
while ((x != root) && (COLOR(PARENT(x)) == RED)) { if (PARENT(x) == LEFT(PARENT(PARENT(x)))) { // Parent of x is a left child with sibling y.
y = RIGHT(PARENT(PARENT(x))); if (COLOR(y) == RED) { // Since y is red, just change everyone's color and try again
// with x's grandfather
COLOR (PARENT (x)) = BLACK; COLOR(y) = BLACK; COLOR(PARENT(PARENT(x))) = RED; x = PARENT(PARENT(x)); } else if (x == RIGHT (PARENT (x))) { // Here y is BLACK and x is a right child. A left rotation
// at x would prepare us for the next case
x = PARENT(x); root = RBLeftRotate (root, x); } else { // Here y is BLACK and x is a left child. We fix the tree by
// switching the colors of x's parent and grandparent and
// doing a right rotation at x's grandparent.
COLOR (PARENT (x)) = BLACK; COLOR (PARENT (PARENT (x))) = RED; root = RBRightRotate (root, PARENT(PARENT(x))); } } else { // Parent of x is a right child with sibling y.
y = LEFT(PARENT(PARENT(x))); if (COLOR(y) == RED) { // Since y is red, just change everyone's color and try again
// with x's grandfather
COLOR (PARENT (x)) = BLACK; COLOR(y) = BLACK; COLOR(PARENT(PARENT(x))) = RED; x = PARENT(PARENT(x)); } else if (x == LEFT (PARENT (x))) { // Here y is BLACK and x is a left child. A right rotation
// at x would prepare us for the next case
x = PARENT(x); root = RBRightRotate (root, x); } else { // Here y is BLACK and x is a right child. We fix the tree by
// switching the colors of x's parent and grandparent and
// doing a left rotation at x's grandparent.
COLOR (PARENT (x)) = BLACK; COLOR (PARENT (PARENT (x))) = RED; root = RBLeftRotate (root, PARENT(PARENT(x))); } } } // end of while loop
COLOR(root) = BLACK; ptree->pRoot= root; }
PKNOWNTYPES RBFind( PRBTREE ptree, char *Name ) /*++
Routine Description:
Finds a node in the red black tree given a name
Arguments:
root - The root of the red/black tree name - The name corresponding to the node to be searched for.
Return Value:
return-value - The node in the tree (entry point of code containing name), or NULL if not found.
--*/ { int i; PKNOWNTYPES root = ptree->pRoot;
while (root != NIL) { i = strcmp(Name, KEY(root)); if (i < 0) { root = LEFT(root); } else if (i > 0) { root = RIGHT(root); } else { return root; } } return NULL; // Range not found
}
PKNOWNTYPES RBTreeSuccessor( PKNOWNTYPES x ) /*++
Routine Description:
Returns the successor of a node in a binary tree (the successor of x is defined to be the node which just follows x in an inorder traversal of the tree).
Arguments:
x - The node whose successor is to be returned
Return Value:
return-value - The successor of x
--*/
{ PKNOWNTYPES y;
// If x has a right child, the successor is the leftmost node to the
// right of x.
if (RIGHT(x) != NIL) { x = RIGHT(x); while (LEFT(x) != NIL) { x = LEFT(x); } return x; } // Else the successor is an ancestor with a left child on the path to x
y = PARENT(x); while ((y != NIL) && (x == RIGHT(y))) { x = y; y = PARENT(y); } return y; }
PKNOWNTYPES RBDeleteFixup( PKNOWNTYPES root, PKNOWNTYPES x ) /*++
Routine Description:
Fixes the red/black tree after a delete operation. Should only be called by RBDelete
Arguments:
root - The root of the red/black tree x - Either a child of x, or or a child or x's successor
Return Value:
return-value - The new root of the red/black tree
--*/ { PKNOWNTYPES w;
// We stop when we either reached the root, or reached a red node (which
// means that property 4 is no longer violated).
while ((x!=root) && (COLOR(x)==BLACK)) { if (x == LEFT(PARENT(x))) { // x is a left child with sibling w
w = RIGHT(PARENT(x)); if (COLOR(w) == RED) { // If w is red it must have black children. We can switch
// the colors of w and its parent and perform a left
// rotation to bring w to the top. This brings us to one
// of the other cases.
COLOR(w) = BLACK; COLOR(PARENT(x)) = RED; root = RBLeftRotate (root, PARENT(x)); w = RIGHT(PARENT(x)); } if ((COLOR(LEFT(w)) == BLACK) && (COLOR(RIGHT(w)) == BLACK)) { // Here w is black and has two black children. We can thus
// change w's color to red and continue.
COLOR(w) = RED; x = PARENT(x); } else { if (COLOR(RIGHT(w)) == BLACK) { // Here w is black, its left child is red, and its right child
// is black. We switch the colors of w and its left child,
// and perform a left rotation at w which brings us to the next
// case.
COLOR(LEFT(w)) = BLACK; COLOR(w) = RED; root = RBRightRotate (root, w); w = RIGHT(PARENT(x)); } // Here w is black and has a red right child. We change w's
// color to that of its parent, and make its parent and right
// child black. Then a left rotation brings w to the top.
// Making x the root ensures that the while loop terminates.
COLOR(w) = COLOR(PARENT(x)); COLOR(PARENT(x)) = BLACK; COLOR(RIGHT(w)) = BLACK; root = RBLeftRotate (root, PARENT(x)); x = root; } } else { // The symmetric case: x is a right child with sibling w.
w = LEFT(PARENT(x)); if (COLOR(w) == RED) { COLOR(w) = BLACK; COLOR(PARENT(x)) = RED; root = RBRightRotate (root, PARENT(x)); w = LEFT(PARENT(x)); } if ((COLOR(LEFT(w)) == BLACK) && (COLOR(RIGHT(w)) == BLACK)) { COLOR(w) = RED; x = PARENT(x); } else { if (COLOR(LEFT(w)) == BLACK) { COLOR(RIGHT(w)) = BLACK; COLOR(w) = RED; root = RBLeftRotate (root, w); w = LEFT(PARENT(x)); } COLOR(w) = COLOR(PARENT(x)); COLOR(PARENT(x)) = BLACK; COLOR(LEFT(w)) = BLACK; root = RBRightRotate (root, PARENT(x)); x = root; } } } // end of while loop
//printf ("Changing color at %i to BLACK\n", x->intelColor);
COLOR(x) = BLACK; return root; }
PKNOWNTYPES RBDelete( PRBTREE ptree, PKNOWNTYPES z ) /*++
Routine Description:
Deletes a node in a red/black tree while preserving the red/black properties.
Arguments:
root - The root of the red/black tree z - The node to be deleted
Return Value:
return-value - The new root of the red/black tree
--*/ { PKNOWNTYPES x,y; PKNOWNTYPES root = ptree->pRoot; COL c;
// It's easy to delete a node with at most one child: we only need to
// remove it and put the child in its place. It z has at most one child,
// we can just remove it. Otherwise we'll replace it with its successor
// (which is guaranteed to have at most one child, or else one of its
// children would be the succecssor), and delete the successor.
if ((LEFT(z) == NIL) || (RIGHT(z) == NIL)) { y = z; } else { y = RBTreeSuccessor(z); }
// Recall that y has at most one child. If y has one child, x is set to
// it. Else x will be set to NIL which is OK. This way we don't have
// to worry about this special case.
if (LEFT(y) != NIL){ x = LEFT(y); } else { x = RIGHT(y); } // Now we will remove y from the tree
PARENT(x) = PARENT(y); if (PARENT(y) == NIL) { root = x; } else if (y == LEFT(PARENT(y))) { LEFT(PARENT(y)) = x; } else { RIGHT(PARENT(y)) = x; }
if (PARENT(x) == z) { PARENT(x) = y; }
c = COLOR(y);
// Since each node has lots of fields (fields may also change during
// the lifetime of this code), I found it safer to copy the
// pointers as opposed to data.
if (y!=z) { // Now swapping y and z, but remembering color of y
PARENT(y) = PARENT(z);
if (root == z) { root = y; } else if (z == RIGHT(PARENT(z))) { RIGHT(PARENT(z)) = y; } else { LEFT(PARENT(z)) = y; }
LEFT(y) = LEFT(z); if (LEFT(y) != NIL) { PARENT(LEFT(y)) = y; }
RIGHT(y) = RIGHT(z); if (RIGHT(y) != NIL) { PARENT(RIGHT(y)) = y; }
COLOR(y) = COLOR(z); }
// Need to fix the tree (fourth red/black property).
if (c == BLACK) { root = RBDeleteFixup (root, x); } return root; }
|