886 lines
28 KiB
C
886 lines
28 KiB
C
// Header file
|
|
#include "RedBlackTreeUtility.h"
|
|
|
|
// constants
|
|
const char SEMICOLON_BREAK[] = "; ";
|
|
const char THICK_DIVIDER = '=';
|
|
const char THIN_DIVIDER = '-';
|
|
|
|
/* Data Structures
|
|
typedef struct RedBlackNodeStruct
|
|
{
|
|
Colors color; (typedef enum { BLACK = 66, RED = 82 } Colors;)
|
|
|
|
char data;
|
|
|
|
struct RedBlackNodeStruct *parentPtr, *leftChildPtr, *rightChildPtr;
|
|
|
|
} RedBlackNodeType;
|
|
|
|
typedef enum { PREORDER_TRAVERSE = 101, INORDER_TRAVERSE = 102,
|
|
POSTORDER_TRAVERSE = 103, NODE_COLOR = 191,
|
|
NODE_DATA = 192 } ControlCodes;
|
|
Data Structures */
|
|
|
|
// functions
|
|
|
|
/*
|
|
Name: clearTree
|
|
Process: recursively returns dynamically allocated data to the OS
|
|
using a post order traversal strategy
|
|
Function input/parameters: working pointer for recursion (RedBlackNodeType *)
|
|
Function output/parameters: none
|
|
Function output/returned: empty tree (NULL)
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: free
|
|
*/
|
|
RedBlackNodeType *clearTree(RedBlackNodeType *localPtr)
|
|
{
|
|
if(localPtr->leftChildPtr != NULL && localPtr->rightChildPtr != NULL)
|
|
{
|
|
clearTree(localPtr->leftChildPtr);
|
|
clearTree(localPtr->rightChildPtr);
|
|
}
|
|
// otherwise, free the local pointer if at end of getting to bottom tree
|
|
free(localPtr);
|
|
// return NULL since no tree left
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
Name: copyTree
|
|
Process: copies a Red Black tree from another Red Black tree
|
|
using a pre order traversal strategy,
|
|
appropriately links child parent pointers to current node
|
|
Function input/parameters: pointer to source node (RedBlackNodeType *)
|
|
Function output/parameters: none
|
|
Function output/returned: pointer to destination node (RedBlackNodeType *)
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: createNodeFromNode, copyTree (recursively)
|
|
*/
|
|
RedBlackNodeType *copyTree(RedBlackNodeType *srcPtr)
|
|
{
|
|
// make a storage pointer
|
|
RedBlackNodeType *copyPtr = NULL;
|
|
// check for not equal to null
|
|
if (srcPtr != NULL)
|
|
{
|
|
// create the pointer given data
|
|
copyPtr = createNodeFromNode(srcPtr);
|
|
// recurse left child
|
|
copyPtr->leftChildPtr = copyTree(srcPtr->leftChildPtr);
|
|
// recurse right child
|
|
copyPtr->rightChildPtr = copyTree(srcPtr->rightChildPtr);
|
|
}
|
|
// return copyPtr
|
|
return copyPtr;
|
|
}
|
|
|
|
/*
|
|
Name: createNodeFromData
|
|
Process: creates a Red Black tree node from the node data given,
|
|
all links are set to NULL
|
|
Function input/parameters: data (char), color (int)
|
|
Function output/parameters: none
|
|
Function output/returned: pointer to created node (RedBlackNodeType *)
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: malloc
|
|
*/
|
|
RedBlackNodeType *createNodeFromData(char data, int nodeColor)
|
|
{
|
|
// define a new node
|
|
RedBlackNodeType *newNode;
|
|
// allocate memory for the newNode (RedBlackNodeType)
|
|
newNode = (RedBlackNodeType*)malloc(sizeof(RedBlackNodeType));
|
|
// define the color as the new node's color
|
|
newNode->color = nodeColor;
|
|
// define the data of the new node to be the input data
|
|
newNode->data = data;
|
|
// set the node's pointers according to spec
|
|
newNode->parentPtr = NULL;
|
|
newNode->leftChildPtr = NULL;
|
|
newNode->rightChildPtr = NULL;
|
|
// return the created node
|
|
return newNode;
|
|
}
|
|
|
|
/*
|
|
Name: createNodeFromNode
|
|
Process: allocates memory for node,
|
|
copies an individual tree node from another node,
|
|
all links are set to NULL
|
|
Function input/parameters: pointer to source node (RedBlackNodeType *)
|
|
Function output/parameters: none
|
|
Function output/returned: pointer to destination node (RedBlackNodeType *)
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: one line of code - createNodeFromData
|
|
*/
|
|
RedBlackNodeType *createNodeFromNode(RedBlackNodeType *srcPtr)
|
|
{
|
|
// return the created node from the given data
|
|
return createNodeFromData(srcPtr->data, srcPtr->color);
|
|
}
|
|
|
|
/*
|
|
Name: displayInOrder
|
|
Process: traverses across tree, prints semicolon-delimited list,
|
|
displays "data / color" using in order strategy
|
|
Function input/parameters: pointer to current working node (RedBlackNodeType *),
|
|
pointer to row start flag
|
|
for first line of output (bool *)
|
|
Function output/parameters: none
|
|
Function output/returned: none
|
|
Device input/---: none
|
|
Device output/---: displayed as specified
|
|
Dependencies: printf, displayInOrder (recursively)
|
|
*/
|
|
void displayInOrder(RedBlackNodeType *wkgPtr, bool *rowStartFlag)
|
|
{
|
|
// check to see if the working pointer is null
|
|
if (wkgPtr != NULL)
|
|
{
|
|
// check to see if the rowStartFlag is true
|
|
if(rowStartFlag)
|
|
{
|
|
// if true, print the order
|
|
printf("Inorder : ");
|
|
// set the rowStartFlag to false
|
|
rowStartFlag = false;
|
|
}
|
|
// recurse to left node in tree
|
|
displayInOrder(wkgPtr->leftChildPtr, rowStartFlag);
|
|
// print out the string
|
|
printf(" %c/%c%s", wkgPtr->data, wkgPtr->color, SEMICOLON_BREAK);
|
|
// recurse to right node in tree
|
|
displayInOrder(wkgPtr->rightChildPtr, rowStartFlag);
|
|
}
|
|
// no return, void.
|
|
}
|
|
|
|
/*
|
|
Name: displayPostOrder
|
|
Process: traverses across tree, prints semicolon-delimited list,
|
|
displays "data / color" using post order strategy
|
|
Function input/parameters: pointer to current working node (RedBlackNodeType *),
|
|
pointer to row start flag
|
|
for first line of output (bool *)
|
|
Function output/parameters: none
|
|
Function output/returned: none
|
|
Device input/---: none
|
|
Device output/---: displayed as specified
|
|
Dependencies: printf, displayPostOrder (recursively)
|
|
*/
|
|
void displayPostOrder(RedBlackNodeType *wkgPtr, bool *rowStartFlag)
|
|
{
|
|
// check to see if the working pointer is null
|
|
if (wkgPtr != NULL)
|
|
{
|
|
// check to see if the rowStartFlag is true
|
|
if (rowStartFlag)
|
|
{
|
|
// if true, print the order
|
|
printf("Postorder: ");
|
|
// set the rowStartFlag to false
|
|
rowStartFlag = false;
|
|
}
|
|
// recurse to left node in tree
|
|
displayPostOrder(wkgPtr->leftChildPtr, rowStartFlag);
|
|
// recurse to right node in tree
|
|
displayPostOrder(wkgPtr->rightChildPtr, rowStartFlag);
|
|
// print out the string
|
|
printf(" %c/%c%s", wkgPtr->data, wkgPtr->color, SEMICOLON_BREAK);
|
|
}
|
|
// no return, void.
|
|
}
|
|
|
|
/*
|
|
Name: displayPreOrder
|
|
Process: traverses across tree, prints semicolon-delimited list,
|
|
displays "data / color" using pre order strategy
|
|
Function input/parameters: pointer to current working node (RedBlackNodeType *),
|
|
pointer to row start flag
|
|
for first line of output (bool *)
|
|
Function output/parameters: none
|
|
Function output/returned: none
|
|
Device input/---: none
|
|
Device output/---: displayed as specified
|
|
Dependencies: printf, displayPreOrder (recursively)
|
|
*/
|
|
void displayPreOrder(RedBlackNodeType *wkgPtr, bool *rowStartFlag)
|
|
{
|
|
// check to see if the working pointer is null
|
|
if (wkgPtr != NULL)
|
|
{
|
|
// check to see if the rowStartFlag is true
|
|
if (rowStartFlag)
|
|
{
|
|
// if true, print the order
|
|
printf("Preorder : ");
|
|
// set the rowStartFlag to false
|
|
rowStartFlag = false;
|
|
}
|
|
// print out the string
|
|
printf(" %c/%c%s", wkgPtr->data, wkgPtr->color, SEMICOLON_BREAK);
|
|
// recurse to left node in tree
|
|
displayPreOrder(wkgPtr->leftChildPtr, rowStartFlag);
|
|
// recurse to right node in tree
|
|
displayPreOrder(wkgPtr->rightChildPtr, rowStartFlag);
|
|
}
|
|
// no return, void.
|
|
}
|
|
|
|
/*
|
|
Name: displayTree
|
|
Process: controller function for calling appropriate tree traversal
|
|
Function input/parameters: pointer to current tree root (RedBlackNodeType *),
|
|
control codes INORDER_TRAVERSE, POSTORDER_TRAVERSE,
|
|
PREORDER_TRAVERSE
|
|
Function output/parameters: none
|
|
Function output/returned: none
|
|
Device input/---: none
|
|
Device output/---: displayed as specified
|
|
Dependencies: displayInOrder, displayPostOrder, displayPreOrder, printf
|
|
*/
|
|
void displayTree(RedBlackNodeType *rootPtr, ControlCodes traverseCode)
|
|
{
|
|
bool rowStarter = true;
|
|
// check to see which ControlCode was used, display based on this.
|
|
if(traverseCode == PREORDER_TRAVERSE)
|
|
{
|
|
printf("\n");
|
|
// use the preorder traversal function
|
|
displayPreOrder(rootPtr, &rowStarter);
|
|
printf("\n");
|
|
}
|
|
else if(traverseCode == INORDER_TRAVERSE)
|
|
{
|
|
printf("\n");
|
|
// use the in order traversal function
|
|
displayInOrder(rootPtr, &rowStarter);
|
|
printf("\n");
|
|
}
|
|
else
|
|
{
|
|
printf("\n");
|
|
// use the postorder traversal function
|
|
displayPostOrder(rootPtr, &rowStarter);
|
|
printf("\n");
|
|
}
|
|
// no return, void.
|
|
}
|
|
|
|
/*
|
|
Name: findTreeHeight
|
|
Process: recursively finds height of tree
|
|
Function input/parameters: working pointer for recursion (RedBlackNodeType *)
|
|
Function output/parameters: none
|
|
Function output/returned: height of tree (int)
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: getMax
|
|
*/
|
|
int findTreeHeight(RedBlackNodeType *localPtr)
|
|
{
|
|
int leftTreeSize, rightTreeSize;
|
|
// check to see if at null
|
|
if(localPtr == NULL)
|
|
{
|
|
// return negative one since either empty or at bottom of tree
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
// traverse the left and right subtrees
|
|
leftTreeSize = findTreeHeight(localPtr->leftChildPtr);
|
|
rightTreeSize = findTreeHeight(localPtr->rightChildPtr);
|
|
// return the max of the subtrees, add one for the local node
|
|
return getMax(leftTreeSize, rightTreeSize) + 1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Name: initializeRBT
|
|
Process: returns NULL to tree root pointer to prepare tree for use
|
|
Function input/parameters: none
|
|
Function output/parameters: none
|
|
Function output/returned: NULL
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: none
|
|
*/
|
|
RedBlackNodeType *initializeRBT()
|
|
{
|
|
// return NULL to begin tree
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
Name: insert
|
|
Process: sets first node if tree is empty, otherwise calls helper
|
|
to set nodes, then calls RBT resolver to rebalance tree
|
|
if node is successfully inserted by helper,
|
|
prints inserting/resolving statement and root color set to black
|
|
Function input/parameters: tree root pointer (RedBlackNodeType *),
|
|
data to be inserted (char)
|
|
Function output/parameters: none
|
|
Function output/returned: pointer to updated tree root (RedBlackNodeType *)
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: printf, createNodeFromData, insertHelper, resolveRBT
|
|
*/
|
|
RedBlackNodeType *insert(RedBlackNodeType *treeRoot, char inData)
|
|
{
|
|
RedBlackNodeType *insertedNode;
|
|
// check if not null
|
|
if(treeRoot != NULL)
|
|
{
|
|
// use insertHelper to get to where the data needs to go
|
|
insertedNode = insertHelper(treeRoot, inData);
|
|
// print out what data is being added, tell user being resolved
|
|
printf("\nInserting %c and resolving\n", inData);
|
|
// use resolveRBT to get the tree balanced correctly
|
|
resolveRBT(&treeRoot, insertedNode);
|
|
}
|
|
else
|
|
{
|
|
// if inserting the root node
|
|
// set the root with createNodeFromData, node is black.
|
|
treeRoot = createNodeFromData(inData, BLACK);
|
|
// tell the user inserting the data
|
|
printf("\nInserting %c and resolving\n", inData);
|
|
// tell the user that the root was set, and is black.
|
|
printf(" - Root color set to black\n");
|
|
/* AN ALTERNATIVE COULD BE TO INSTEAD
|
|
USE THE RESOLVE FUNCTION INSTEAD OF DOING IT BY HAND*/
|
|
}
|
|
// return treeRoot
|
|
return treeRoot;
|
|
}
|
|
|
|
/*
|
|
Name: insertHelper
|
|
Process: recursively finds place to add node,
|
|
places node using "look down" strategy,
|
|
returns newly inserted node pointer,
|
|
if duplicated nodes/keys attempted, returns NULL
|
|
Function input/parameters: working pointer for recursion (RedBlackNodeType *),
|
|
data to be inserted (char)
|
|
Function output/parameters: none
|
|
Function output/returned: pointer to inserted node (RedBlackNodeType *)
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: createNodeFromData, insertHelper (recursively)
|
|
*/
|
|
RedBlackNodeType *insertHelper(RedBlackNodeType *wkgPtr, char inData)
|
|
{
|
|
// compare between current node and inData
|
|
int diffChar = inData - wkgPtr->data;
|
|
|
|
// check for moving left (diffChar < 0)
|
|
if(diffChar < 0)
|
|
{
|
|
// check for left child NULL
|
|
if(wkgPtr->leftChildPtr == NULL)
|
|
{
|
|
// assign current left child to a new node
|
|
wkgPtr->leftChildPtr = createNodeFromData(inData, RED);
|
|
// return pointer to the node added
|
|
return wkgPtr->leftChildPtr;
|
|
}
|
|
// return recursion
|
|
return insertHelper(wkgPtr->leftChildPtr, inData);
|
|
}
|
|
// otherwise, check for moving right (diffChar > 0)
|
|
else if(diffChar > 0)
|
|
{
|
|
// check for right child NULL
|
|
if(wkgPtr->rightChildPtr == NULL)
|
|
{
|
|
// assign current right child to a new node
|
|
wkgPtr->rightChildPtr = createNodeFromData(inData, RED);
|
|
// return pointer to the node added
|
|
return wkgPtr->rightChildPtr;
|
|
}
|
|
// return recursion
|
|
return insertHelper(wkgPtr->rightChildPtr, inData);
|
|
}
|
|
// otherwise, there is a duplicate
|
|
// return NULL
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
Name: isEmpty
|
|
Process: returns true if tree is empty, false otherwise
|
|
Function input/parameters: tree root pointer (RedBlackNodeType *)
|
|
Function output/parameters: none
|
|
Function output/returned: result of test (bool)
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: none
|
|
*/
|
|
bool isEmpty(RedBlackNodeType *localPtr)
|
|
{
|
|
// return test of root pointer is NULL
|
|
return localPtr == NULL;
|
|
}
|
|
|
|
/*
|
|
Name: resolveRBT
|
|
Process: recursively checks tree for need to rebalance,
|
|
conducts rebalance as needed
|
|
Function input/parameters: address of tree root pointer (RedBlackNodeType **),
|
|
working pointer for recursion
|
|
which starts at the location
|
|
of the inserted node (RedBlackNodeType *)
|
|
Function output/parameters: none
|
|
Function output/returned: none
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: printf, rotateLeft, rotateRight, swapColors,
|
|
displayTreeStructure, displayDivider
|
|
*/
|
|
void resolveRBT(RedBlackNodeType **treeRoot, RedBlackNodeType *wkgPtr)
|
|
{
|
|
printf("\nAttempting to Resolve RBT\n");
|
|
// declare parPtr, grndParPtr, unclePtr, grtGrndPtr
|
|
RedBlackNodeType *wkgParentPtr;
|
|
RedBlackNodeType *wkgGrandParentPtr;
|
|
RedBlackNodeType *wkgUnclePtr;
|
|
RedBlackNodeType *wkgGreatGrandParentPtr;
|
|
// check for parent and grandparent exists
|
|
if(wkgPtr->parentPtr != NULL && wkgPtr->parentPtr->parentPtr != NULL)
|
|
{
|
|
printf("\nStarting resolution process.\n");
|
|
// set all my relatives, will need to know which child I am
|
|
wkgParentPtr = wkgPtr->parentPtr;
|
|
wkgGrandParentPtr = wkgParentPtr->parentPtr;
|
|
if (wkgParentPtr->leftChildPtr == wkgPtr)
|
|
{
|
|
// set the uncle pointer to the parent's right child
|
|
wkgUnclePtr = wkgParentPtr->rightChildPtr;
|
|
}
|
|
else
|
|
{
|
|
// set the uncle pointer to the parent's left child
|
|
wkgUnclePtr = wkgParentPtr->leftChildPtr;
|
|
}
|
|
wkgGreatGrandParentPtr = wkgGrandParentPtr->parentPtr;
|
|
// check for red uncle
|
|
if(wkgUnclePtr != NULL && wkgUnclePtr->color == RED)
|
|
{
|
|
// change parent and uncle to black
|
|
wkgParentPtr->color = BLACK;
|
|
wkgUnclePtr->color = BLACK;
|
|
// change grandparent to red
|
|
wkgGrandParentPtr->color = RED;
|
|
// recurse with the grandparent
|
|
resolveRBT(treeRoot, wkgGrandParentPtr);
|
|
}
|
|
// otherwise, assume uncle is black
|
|
else
|
|
{
|
|
// check for parent is left of grandparent
|
|
if(wkgGrandParentPtr->leftChildPtr == wkgParentPtr)
|
|
{
|
|
// check for child is left of parent (Left Left case)
|
|
if(wkgParentPtr->leftChildPtr == wkgPtr)
|
|
{
|
|
printf("\nLL Case, rotate right\n");
|
|
// use rotate right with grandparent(old) and parent(new)
|
|
// link the parent to grandparent's parent
|
|
// swap colors called with parent and grandparent
|
|
}
|
|
// check for child is right of parent (Left Right case)
|
|
else
|
|
{
|
|
printf("\nLR Case, rotate right, recurse\n");
|
|
// use rotate right with parent(old) and createdNode(new)
|
|
// call resolveRBT with parent as createdNode (will treat as LLC)
|
|
}
|
|
}
|
|
// check for parent is right of grandparent
|
|
else
|
|
{
|
|
// check for child is right of parent (Right Right case)
|
|
if(wkgParentPtr->rightChildPtr == wkgPtr)
|
|
{
|
|
printf("\nRR Case, rotate left\n");
|
|
// use rotate left with grandparent(old) and parent(new)
|
|
// link the parent to grandparent's parent
|
|
// swap colors called with parent and grandparent
|
|
}
|
|
// check for child is left of parent (Right Left case)
|
|
else
|
|
{
|
|
printf("\nRL Case, rotate left, recurse\n");
|
|
// use rotate left with parent(old) and createdNode(new)
|
|
// call resolveRBT with parent as createdNode (will treat as RRC)
|
|
}
|
|
}
|
|
}
|
|
// end of par/gpr test
|
|
}
|
|
// check for current node is root pointer
|
|
if(wkgPtr == *treeRoot)
|
|
{
|
|
// paint it black
|
|
wkgPtr->color = BLACK;
|
|
}
|
|
// print out the structure, version data
|
|
displayTreeStructure(*treeRoot, NODE_DATA);
|
|
// print the thin divider
|
|
displayDivider(*treeRoot, THIN_DIVIDER);
|
|
// print out the structure, version color
|
|
displayTreeStructure(*treeRoot, NODE_COLOR);
|
|
// print the thick divider
|
|
displayDivider(*treeRoot, THICK_DIVIDER);
|
|
// no return, void.
|
|
}
|
|
|
|
/*
|
|
Name: rotateLeft
|
|
Process: "rotates" nodes to the left by resetting pointers
|
|
to related nodes
|
|
Function input/parameters: old and new top node pointers (RedBlackNodeType *)
|
|
Function output/parameters: none
|
|
Function output/returned: pointer to new top node (RedBlackNodeType *)
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: none
|
|
*/
|
|
RedBlackNodeType *rotateLeft(RedBlackNodeType *newTopPtr,
|
|
RedBlackNodeType *oldTopPtr)
|
|
{
|
|
// set the old top's parent's right child to the new top
|
|
oldTopPtr->parentPtr->rightChildPtr = newTopPtr;
|
|
// set the old top's right child to the new top's left child
|
|
oldTopPtr->rightChildPtr = newTopPtr->leftChildPtr;
|
|
// set the new top's parent to old top's parent
|
|
newTopPtr->parentPtr = oldTopPtr->parentPtr;
|
|
// set the new top's left child to old top
|
|
newTopPtr->leftChildPtr = oldTopPtr;
|
|
// set the old top's parent to new top
|
|
oldTopPtr->parentPtr = newTopPtr;
|
|
// return new top
|
|
return newTopPtr;
|
|
}
|
|
|
|
/*
|
|
Name: rotateRight
|
|
Process: "rotates" nodes to the right by resetting pointers
|
|
to related nodes
|
|
Function input/parameters: old and new top node pointers (RedBlackNodeType *)
|
|
Function output/parameters: none
|
|
Function output/returned: pointer to new top node (RedBlackNodeType *)
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: none
|
|
*/
|
|
RedBlackNodeType *rotateRight(RedBlackNodeType *newTopPtr,
|
|
RedBlackNodeType *oldTopPtr)
|
|
{
|
|
// set the old top's parent's left child to the new top
|
|
oldTopPtr->parentPtr->leftChildPtr = newTopPtr;
|
|
// set the old top's left child to the new top's right child
|
|
oldTopPtr->leftChildPtr = newTopPtr->rightChildPtr;
|
|
// set the new top's parent to old top's parent
|
|
newTopPtr->parentPtr = oldTopPtr->parentPtr;
|
|
// set the new top's right child to old top
|
|
newTopPtr->rightChildPtr = oldTopPtr;
|
|
// set the old top's parent to new top
|
|
oldTopPtr->parentPtr = newTopPtr;
|
|
// return new top
|
|
return newTopPtr;
|
|
}
|
|
|
|
/*
|
|
Name: swapColors
|
|
Process: swaps or exchanges colors between two nodes
|
|
Function input/parameters: pointers to two nodes (RedBlackNodeType *)
|
|
Function output/parameters: none
|
|
Function output/returned: updated pointers to two nodes (RedBlackNodeType *)
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: none
|
|
*/
|
|
void swapColors(RedBlackNodeType *one, RedBlackNodeType *other)
|
|
{
|
|
// define temporary holding place for one color
|
|
int tempColor = one->color;
|
|
// swap the colors using the temp.
|
|
one->color = other->color;
|
|
other->color = tempColor;
|
|
// no return, void.
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// No student coding below this point
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
Name: displayAtTreeLevel
|
|
Process: displays one horizontal "level" of a tree using text graphics
|
|
with appropriate spacing and appropriate number of nodes
|
|
Function input/parameters: recursive working node (RedBlackNodeType *),
|
|
node height, display level, working level (int),
|
|
row start flag (bool),
|
|
control code for either data or color
|
|
Function output/parameters: none
|
|
Function output/returned: updated row start flag (bool *)
|
|
Device input/file: none
|
|
Device output/monitor: none
|
|
Dependencies: displayValue, displayEmptyNodeSpaces
|
|
*/
|
|
void displayAtTreeLevel( RedBlackNodeType *workingNode, int nodeHeight,
|
|
int displayLevel, int workingLevel,
|
|
bool *rowStartFlag, ControlCodes ctrlCode )
|
|
{
|
|
char charOut = workingNode->data;
|
|
|
|
if( ctrlCode == NODE_COLOR )
|
|
{
|
|
charOut = (char)workingNode->color;
|
|
}
|
|
|
|
if( workingLevel == displayLevel )
|
|
{
|
|
displayValue( charOut, nodeHeight, workingLevel, rowStartFlag );
|
|
}
|
|
|
|
else
|
|
{
|
|
if( workingNode->leftChildPtr != NULL )
|
|
{
|
|
displayAtTreeLevel( workingNode->leftChildPtr, nodeHeight,
|
|
displayLevel, workingLevel + 1, rowStartFlag, ctrlCode );
|
|
}
|
|
|
|
else
|
|
{
|
|
displayEmptyNodeSpaces( nodeHeight, displayLevel,
|
|
workingLevel + 1, rowStartFlag, ctrlCode );
|
|
}
|
|
|
|
if( workingNode->rightChildPtr != NULL )
|
|
{
|
|
displayAtTreeLevel( workingNode->rightChildPtr, nodeHeight,
|
|
displayLevel, workingLevel + 1, rowStartFlag, ctrlCode );
|
|
}
|
|
|
|
else
|
|
{
|
|
displayEmptyNodeSpaces( nodeHeight, displayLevel,
|
|
workingLevel + 1, rowStartFlag, ctrlCode );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Name: displayChars
|
|
Process: recursively displays a specified number of specified characters
|
|
Function input/parameters: number of characters (int),
|
|
character to be displayed (char)
|
|
Function output/parameters: none
|
|
Function output/returned: none
|
|
Device input/file: none
|
|
Device output/monitor: characters displayed as specified
|
|
Dependencies: printf
|
|
*/
|
|
void displayChars( int numChars, char outChar )
|
|
{
|
|
if( numChars > 0 )
|
|
{
|
|
printf( "%c", outChar );
|
|
|
|
displayChars( numChars - 1, outChar );
|
|
}
|
|
}
|
|
|
|
/*
|
|
Name: displayDivider
|
|
Process: displays divider of correct length for tree
|
|
using either THICK_DIVIDER or THIN_DIVIDER
|
|
depending on the control code,
|
|
adds one endline to thick divider, two to thin for spacing
|
|
Function input/parameters: number of characters (int),
|
|
character to be displayed (char)
|
|
Function output/parameters: none
|
|
Function output/returned: none
|
|
Device input/file: none
|
|
Device output/monitor: characters displayed as specified
|
|
Dependencies: printf
|
|
*/
|
|
void displayDivider( RedBlackNodeType *rootPtr, char dividerChar )
|
|
{
|
|
int treeHeight = findTreeHeight( rootPtr );
|
|
int numChars = toPower( 2, treeHeight + 2 );
|
|
|
|
displayChars( numChars, dividerChar );
|
|
|
|
if( dividerChar == THIN_DIVIDER )
|
|
{
|
|
printf( "\n" );
|
|
}
|
|
|
|
printf( "\n" );
|
|
}
|
|
|
|
/*
|
|
Name: displayEmptyNodeSpaces
|
|
Process: displays the appropriate number of dashes for a given level
|
|
for null nodes, can display either dashes or 'B's
|
|
Function input/parameters: node height, display level, working level (int)
|
|
pointer to row start flag (bool *),
|
|
control code for either data or color
|
|
Function output/parameters: none
|
|
Function output/returned: updated row start flag (bool *)
|
|
Device input/file: none
|
|
Device output/monitor: characters displayed as specified
|
|
Dependencies: toPower, displayValue
|
|
*/
|
|
void displayEmptyNodeSpaces( int nodeHeight,
|
|
int displayLevel, int workingLevel,
|
|
bool *rowStartFlag, ControlCodes ctrlCode )
|
|
{
|
|
int nodesToDisplay = toPower( 2, displayLevel - workingLevel );
|
|
char charOut = SPACE;
|
|
|
|
if( displayLevel == workingLevel )
|
|
{
|
|
charOut = DASH;
|
|
|
|
if( ctrlCode == NODE_COLOR )
|
|
{
|
|
charOut = 'B';
|
|
}
|
|
}
|
|
|
|
while( nodesToDisplay > 0 )
|
|
{
|
|
displayValue( charOut, nodeHeight, displayLevel, rowStartFlag );
|
|
|
|
nodesToDisplay--;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Name: displayTreeStructure
|
|
Process: repeatedly calls other function to display
|
|
the structure of an RB tree, can display either dashes or 'B's,
|
|
displays error message if empty tree
|
|
Function input/parameters: tree root pointer (RedBlackNodeType *),
|
|
control code for either data or color
|
|
Function output/parameters: none
|
|
Function output/returned: none
|
|
Device input/file: none
|
|
Device output/monitor: characters displayed as specified
|
|
Dependencies: findTreeHeight, displayAtTreeLevel, printf
|
|
*/
|
|
void displayTreeStructure( RedBlackNodeType *rbTreeRoot, ControlCodes ctrlCode )
|
|
{
|
|
int displayLevel, nodeHeight = findTreeHeight( rbTreeRoot ) + 2;
|
|
int workingLevel = 1;
|
|
bool rowStartFlag;
|
|
|
|
if( rbTreeRoot != NULL )
|
|
{
|
|
for( displayLevel = 1; displayLevel <= nodeHeight; displayLevel++ )
|
|
{
|
|
rowStartFlag = true;
|
|
|
|
displayAtTreeLevel( rbTreeRoot, nodeHeight,
|
|
displayLevel, workingLevel, &rowStartFlag, ctrlCode );
|
|
|
|
printf( "\n" );
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
printf( "\nEmpty Tree - No Display" );
|
|
}
|
|
}
|
|
|
|
/*
|
|
Name: displayValue
|
|
Process: displays a tree character value or color letter (R/B)
|
|
after a calculated set of leading spaces
|
|
Function input/parameters: character data (char),
|
|
node height, working level (int),
|
|
pointer to row start flag (bool *)
|
|
Function output/parameters: updated row start flag (bool *)
|
|
Function output/returned: none
|
|
Device input/file: none
|
|
Device output/monitor: character displayed as specified
|
|
Dependencies: toPower, displayChars, printf
|
|
*/
|
|
void displayValue( char data, int nodeHeight,
|
|
int workingLevel, bool *rowStartFlag )
|
|
{
|
|
int leadingSpaces;
|
|
|
|
if( *rowStartFlag )
|
|
{
|
|
leadingSpaces = toPower( 2, nodeHeight - workingLevel );
|
|
|
|
*rowStartFlag = false;
|
|
}
|
|
|
|
else
|
|
{
|
|
leadingSpaces = toPower( 2, nodeHeight - workingLevel + 1 ) - 1;
|
|
}
|
|
|
|
displayChars( leadingSpaces, SPACE );
|
|
|
|
printf( "%c", data );
|
|
}
|
|
|
|
/*
|
|
Name: getMax
|
|
Process: finds the maximum between two values, returns
|
|
Function input/parameters: two values (int)
|
|
Function output/parameters: none
|
|
Function output/returned: maximum of two values (int)
|
|
Device input/file: none
|
|
Device output/monitor: none
|
|
Dependencies: none
|
|
*/
|
|
int getMax( int one, int other )
|
|
{
|
|
int max = one;
|
|
|
|
if( other > max )
|
|
{
|
|
max = other;
|
|
}
|
|
|
|
return max;
|
|
}
|
|
|
|
/*
|
|
Name: toPower
|
|
Process: recursively calculates a base to exponent value
|
|
for positive integer exponents
|
|
Function input/parameters: base, exponent (int)
|
|
Function output/parameters: none
|
|
Function output/returned: calculated value (int)
|
|
Device input/file: none
|
|
Device output/monitor: none
|
|
Dependencies: none
|
|
*/
|
|
int toPower( int base, int exponent )
|
|
{
|
|
if( exponent > 0 )
|
|
{
|
|
return toPower( base, exponent - 1 ) * base;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|