Introduction to algorithms is good, but it is a headache to read pseudocode. I always want to have a c-language version of Introduction to algorithms.
I studied the red/black tree a few days ago and translated it into C language. Compiled and tested on vc6.0. A cview class is written to show the effect.
Header file rb_tree.h
# Ifndef rb_tree_h
# Define rb_tree_h
Enum nodecolor {Red = 0, black = 1 };
Typedef int nodedata;
Struct rb_tree_node
{
Nodecolor color;
Int key;
Nodedata Info;
Rb_tree_node * left;
Rb_tree_node * right;
Rb_tree_node * parent;
};
Struct rb_tree
{
Rb_tree_node * root;
Rb_tree_node * nil;
};
Void init_rb_tree (rb_tree * t );
Void left_rotate (rb_tree * t, rb_tree_node * X );
Void right_rotate (rb_tree * t, rb_tree_node * X );
Void rb_insert (rb_tree * t, int key, nodedata info = 0 );
Void rb_insert _ (rb_tree * t, rb_tree_node * z );
Void rb_insert_fixup (rb_tree * t, rb_tree_node * z );
Void rb_delete (rb_tree * t, int key );
Void rb_delete _ (rb_tree * t, rb_tree_node * z );
Void rb_delete_fixup (rb_tree * t, rb_tree_node * X );
Int get_tree_height (rb_tree * t, rb_tree_node * X );
# Endif
Implementation file: rb_tree.cpp
/*
Implementation of the red/black tree, based on pseudo-code translation in introduction to Algorithms
Author: Hu weichen huweichen@163.com
Time: 2010.6.26
*/
# Include <stdlib. h>
// # Include <malloc. h>
# Include "rb_tree.h"
Void init_rb_tree (rb_tree * t)
{
Rb_tree_node * node = new rb_tree_node;
Node-> color = black;
Node-> info = 0;
Node-> key = 0;
Node-> left = 0;
Node-> parent = 0;
Node-> right = 0;
T-> nil = node;
T-> root = T-> nil;
}
Int get_tree_height (rb_tree * t, rb_tree_node * X)
{
Int LH = 0;
Int RH = 0;
If (X-> left! = T-> nil)
{
LH = get_tree_height (t, x-> left );
}
If (X-> right! = T-> nil)
{
RH = get_tree_height (t, x-> right );
}
If (LH> RH)
{
Return LH + 1;
}
Else
{
Return rh + 1;
}
}
Void left_rotate (rb_tree * t, rb_tree_node * X)
{
Rb_tree_node * Y = x-> right;
X-> right = Y-> left;
If (Y-> left! = T-> nil)
{
Y-> left-> parent = X;
}
Y-> parent = x-> parent;
If (X-> parent = T-> nil)
{
T-> root = y;
}
Else if (x = x-> parent-> left)
{
X-> parent-> left = y;
}
Else
{
X-> parent-> right = y;
}
Y-> left = X;
X-> parent = y;
}
Void right_rotate (rb_tree * t, rb_tree_node * X)
{
Rb_tree_node * Y = x-> left;
// Use the right child node of the left child node as the left child node
X-> left = Y-> right;
If (Y-> right! = T-> nil)
{
Y-> right-> parent = X;
}
// Replace the original left subnode with its own position.
Y-> parent = x-> parent;
If (X-> parent = T-> nil)
{
T-> root = y;
}
Else if (x = x-> parent-> right)
{
X-> parent-> right = y;
}
Else
{
X-> parent-> left = y;
}
// Use yourself as the right subnode of the original left subnode
Y-> right = X;
X-> parent = y;
}
Void rb_insert (rb_tree * t, int key, nodedata info)
{
Rb_tree_node * node = new rb_tree_node;
Node-> key = key;
Node-> info = Info;
Rb_insert _ (T, node );
}
Void rb_insert _ (rb_tree * t, rb_tree_node * z)
{
Rb_tree_node * Y = T-> nil;
Rb_tree_node * x = T-> root;
// Find a suitable Insert Location
While (X! = T-> nil)
{
Y = X;
If (Z-> key = x-> key)
{
Delete Z;
Return;
}
Else if (Z-> key <X-> key)
{
X = x-> left;
}
Else
{
X = x-> right;
}
}
// Insert a node
Z-> parent = y;
If (y = T-> nil)
{
T-> root = z;
}
Else if (Z-> key <Y-> key)
{
Y-> left = z;
}
Else
{
Y-> right = z;
}
// Assign values to other fields of the new node
Z-> left = T-> nil;
Z-> right = T-> nil;
Z-> color = Red;
// Modify the tree to meet the needs of the red/black tree
Rb_insert_fixup (T, Z );
}
Void rb_insert_fixup (rb_tree * t, rb_tree_node * z)
{
Rb_tree_node * Y = T-> nil;
// Loop until the parent node is black
While (Z-> parent-> color = red)
{
// If the parent node is the left child node of the grandfather Node
If (Z-> parent = z-> parent-> left)
{
Y = z-> parent-> right;
// If the uncle node is red, set both the father node and the uncle node to black and the grandfather node to red.
If (Y-> color = red)
{
Z-> parent-> color = black;
Y-> color = black;
Z-> parent-> color = Red;
Z = z-> parent;
}
// If the uncle node is black, the father node is black and the grandfather node is red,
// Then rotate right to make the grandfather node become an uncle Node
Else
{
// If it is a right sub-node, first rotate left, so that the following right rotation will be symmetric
If (Z = z-> parent-> right)
{
Z = z-> parent;
Left_rotate (T, Z );
}
Z-> parent-> color = black;
Z-> parent-> color = Red;
Right_rotate (T, Z-> parent );
}
}
// The following code is symmetric with the above Code
Else
{
Y = z-> parent-> left;
If (Y-> color = red)
{
Z-> parent-> color = black;
Y-> color = black;
Z-> parent-> color = Red;
Z = z-> parent;
}
Else
{
If (Z = z-> parent-> left)
{
Z = z-> parent;
Right_rotate (T, Z );
}
Z-> parent-> color = black;
Z-> parent-> color = Red;
Left_rotate (T, Z-> parent );
}
}
}
T-> root-> color = black;
}
Rb_tree_node * find_node (rb_tree * t, int key)
{
Rb_tree_node * x = T-> root;
While (X! = T-> nil)
{
If (Key = x-> key)
{
Return X;
}
Else if (Key <X-> key)
{
X = x-> left;
}
Else
{
X = x-> right;
}
}
Return T-> nil;
}
Void rb_delete (rb_tree * t, int key)
{
Rb_tree_node * x = find_node (T, key );
If (X! = T-> nil)
{
Rb_delete _ (t, x );
}
}
Rb_tree_node * tree_minimum (rb_tree * t, rb_tree_node * X)
{
While (X-> left! = T-> nil)
{
X = x-> left;
}
Return X;
}
Rb_tree_node * tree_successor (rb_tree * t, rb_tree_node * X)
{
Rb_tree_node * Y = T-> nil;
If (X-> right! = T-> nil)
{
Return tree_minimum (t, x-> right );
}
Y = x-> parent;
While (y! = T-> nil & X = Y-> right)
{
X = y;
Y = Y-> parent;
}
Return y;
}
Void rb_delete _ (rb_tree * t, rb_tree_node * z)
{
Rb_tree_node * Y = T-> nil;
Rb_tree_node * x = T-> nil;
// As long as Z has a byte point that is not null, Y is equal to Z; otherwise, Y is a rear drive of Z.
If (Z-> left = T-> nil | Z-> right = T-> nil)
{
Y = z;
}
Else
{
Y = tree_successor (T, Z );
}
// Set X to a subnode of Y, which may also be nil.
If (Y-> left! = T-> nil)
{
X = Y-> left;
}
Else
{
X = Y-> right;
}
// Delete y from the tree, but do not release y's memory temporarily, because it will be used later
X-> parent = Y-> parent;
If (Y-> parent = T-> nil)
{
T-> root = X;
}
Else
{
If (y = Y-> parent-> left)
{
Y-> parent-> left = X;
}
Else
{
Y-> parent-> right = X;
}
}
// If y is not equal to Z, but a rear drive of Z, copy the keyword and data of Y to Z.
If (y! = Z)
{
Z-> key = Y-> key;
Z-> info = Y-> Info;
}
// If the deleted y node is a black node, the red and black properties of the tree will be damaged, that is, the black height will change, and you need to adjust it.
If (Y-> color = black)
{
Rb_delete_fixup (t, x );
}
// In this case, the memory occupied by Y can be released.
Delete y;
}
Void rb_delete_fixup (rb_tree * t, rb_tree_node * X)
{
Rb_tree_node * w = T-> nil;
// The color of X must be adjusted only when it is black. If X is red, set it to black.
While (X! = T-> root & X-> color = black)
{
If (x = x-> parent-> left)
{
// Set w as a brother Node
W = x-> parent-> right;
// If W is red, set w to black, set w's parent node to red, and then rotate the parent node left.
If (W-> color = red)
{
W-> color = black;
X-> parent-> color = Red;
Left_rotate (t, x-> parent );
W = x-> parent-> right;
}
// If both left and right child nodes of W are black, set w to red and set X to the parent node of X,
// At this time, the black height of the left and right child nodes of the new x is the same, that is, X is a red and black tree, but the brother node of the new x
// The Black height is still large, so continue to adjust the next cycle
If (W-> left-> color = Black & W-> right-> color = black)
{
W-> color = Red;
X = x-> parent;
}
Else
{
// If the left subnode of W is red and the right subnode is black, set w to red first and black to the left subnode,
// Then rotate right to prepare for the left rotation below
If (W-> right-> color = black)
{
W-> left-> color = black;
W-> color = Red;
Right_rotate (T, W );
W = x-> parent-> right;
}
// Set w as the color of the parent node, so that the color of the New and Old parent nodes remains unchanged after the left rotation below,
// Set w's parent node and right child node to black, and then rotate left,
// In this way, the black height of the Left subnode and the right subnode is the same, so you do not need to adjust it. Therefore, set X to root.
W-> color = x-> parent-> color;
X-> parent-> color = black;
W-> right-> color = black;
Left_rotate (t, x-> parent );
X = T-> root;
}
}
// The following code is symmetric with the above Code
Else
{
W = x-> parent-> left;
If (W-> color = red)
{
W-> color = black;
X-> parent-> color = Red;
Right_rotate (t, x-> parent );
W = x-> parent-> left;
}
If (W-> right-> color = Black & W-> left-> color = black)
{
W-> color = Red;
X = x-> parent;
}
Else
{
If (W-> left-> color = black)
{
W-> right-> color = black;
W-> color = Red;
Left_rotate (T, W );
W = x-> parent-> left;
}
W-> color = x-> parent-> color;
X-> parent-> color = black;
W-> left-> color = black;
Right_rotate (t, x-> parent );
X = T-> root;
}
}
}
X-> color = black;
}
Ctestrbtreeview class used to display the test results
Void ctestrbtreeview: ondraw (CDC * PDC)
{
Ctestrbtreedoc * pdoc = getdocument ();
Assert_valid (pdoc );
If (rb_tree1.root = rb_tree1.nil)
Return;
Crect rcclient;
Getclientrect (& rcclient );
Int x = rcclient. Width ()/2;
Int y = 30;
Int level = get_tree_height (& rb_tree1, rb_tree1.root );
Drawrbtree (PDC, & rb_tree1, rb_tree1.root, level, x, y );
}
# Define nodedistance 24
# Define radius 20
Void ctestrbtreeview: drawrbtree (CDC * PDC, rb_tree * t, rb_tree_node * node, int level, int X, int y)
{
If (node = T-> nil)
Return;
Cpen pen;
Cpen penblue;
Penblue. createpen (ps_solid, 1, colorref (0xff0000 ));
If (node-> left! = T-> nil)
{
Int xleft = x-(nodedistance * (POW (2, level)-1)/4;
PDC-> SelectObject (& penblue );
PDC-> moveTo (x, y );
PDC-> lineto (xleft, Y + 60 );
Drawrbtree (PDC, T, node-> left, level-1, xleft, Y + 60 );
}
If (node-> right! = T-> nil)
{
Int xright = x + (nodedistance * (POW (2, level)-1)/4;
PDC-> SelectObject (& penblue );
PDC-> moveTo (x, y );
PDC-> lineto (xright, Y + 60 );
Drawrbtree (PDC, T, node-> right, level-1, xright, Y + 60 );
}
If (node-> color = red)
{
PDC-> settextcolor (0x0000ff );
Pen. createpen (ps_solid, 1, 0x0000ff );
}
Else
{
PDC-> settextcolor (0 );
Pen. createpen (ps_solid, 1, colorref (0 ));
}
PDC-> SelectObject (& pen );
Crect rect;
Rect. Left = x-12;
Rect. Top = Y-12;
Rect. Right = x + 12;
Rect. Bottom = Y + 12;
PDC-> ellipse (& rect );
Cstring STR;
Str. Format ("% d", node-> key );
If (node-> key <10)
{
PDC-> textout (X-4, Y-8, STR );
}
Else
{
PDC-> textout (X-8, Y-8, STR );
}
}