windows-nt/Source/XPSP1/NT/base/wow64/tools/genlib/redblack.c
2020-09-26 16:20:57 +08:00

598 lines
14 KiB
C

/*++
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;
}