2020-05-08 UPDATE
通过一点一点的debug,终于发现红黑树CASE 3中存在的隐藏情况。通过对CASE 3中的隐藏情况进行处理,顺利构造出了红黑树,并通过了测试用例。将代码贴在下面与大家共同学习。
代码
#include <stdio.h>
#include <stdlib.h>
#define LEN 100000
#define NEGATIVEINFINITY -1.0*RAND_MAX
enum COLOR {RED, BLACK};
typedef struct BRNODE{
COLOR color;
float value;
struct BRNODE *left;
struct BRNODE *right;
struct BRNODE *parent;
int height=0;
int smallerThanCurrentNode = -1;
}brNode, *pointerBrNode;
void inorder(pointerBrNode p2);
void preorder(pointerBrNode p2);
pointerBrNode root = NULL;
pointerBrNode constructNode(float insertValue, pointerBrNode parent)
{
pointerBrNode p = (pointerBrNode)malloc(sizeof(brNode));
p->value = insertValue;
p->color = RED;
p->parent = parent;
//nil左子节点
p->left = (pointerBrNode)malloc(sizeof(brNode));
p->left->value = NEGATIVEINFINITY;
p->left->color = BLACK;
p->left->left = NULL;
p->left->right = NULL;
p->left->parent = p;
//nil右子节点
p->right = (pointerBrNode)malloc(sizeof(brNode));
p->right->value = NEGATIVEINFINITY;
p->right->color = BLACK;
p->right->left = NULL;
p->right->right = NULL;
p->right->parent = p;
return p;
}
void adjust(pointerBrNode currentCollisionNode)
{
//currentCollisionNode->parent->parent == NULL 容易出错
while(currentCollisionNode->parent->value > 0.0 && currentCollisionNode->color == RED) {
if (currentCollisionNode->parent->color == BLACK)
return;
if (currentCollisionNode->parent->parent->left == currentCollisionNode->parent) {
//case 1
if (currentCollisionNode->parent->parent->right->color == RED) {
currentCollisionNode->parent->color = BLACK;
currentCollisionNode->parent->parent->right->color = BLACK;
currentCollisionNode->parent->parent->color = RED;
currentCollisionNode = currentCollisionNode->parent->parent;
} else {
if (currentCollisionNode->parent->right == currentCollisionNode) {
//case 2 left rotation
pointerBrNode tmp = currentCollisionNode->left;
currentCollisionNode->parent->parent->left = currentCollisionNode;
currentCollisionNode->left = currentCollisionNode->parent;
currentCollisionNode->parent = currentCollisionNode->left->parent;
currentCollisionNode->left->parent = currentCollisionNode;
currentCollisionNode->left->right = tmp;
currentCollisionNode->left->right->parent = currentCollisionNode->left;
currentCollisionNode = currentCollisionNode->left;
//printf("when collision node is:%f, %f, %f\n", currentCollisionNode->value, currentCollisionNode->parent->value, currentCollisionNode->parent->parent->value);
} else {
//case 3 right rotation
pointerBrNode tmp = currentCollisionNode->parent->right;
currentCollisionNode->parent->right = currentCollisionNode->parent->parent;
if (currentCollisionNode->parent->parent==currentCollisionNode->parent->parent->parent->left) {
currentCollisionNode->parent->parent->parent->left = currentCollisionNode->parent;
} else {
currentCollisionNode->parent->parent->parent->right = currentCollisionNode->parent;
}
currentCollisionNode->parent->parent = currentCollisionNode->parent->parent->parent;
currentCollisionNode->parent->right->parent = currentCollisionNode->parent;
//currentCollisionNode->parent->parent->right误写成了left;
//currentCollisionNode->parent->parent->left误写成了right
currentCollisionNode->parent->right->left = tmp;
currentCollisionNode->parent->right->left->parent = currentCollisionNode->parent->right;
currentCollisionNode = currentCollisionNode->parent;
currentCollisionNode->color = BLACK;
currentCollisionNode->right->color = RED;
//printf("when collision node is:%d, %d, %d\n", currentCollisionNode->color, currentCollisionNode->left->color, currentCollisionNode->right->color);
}
}
} else {
if (currentCollisionNode->parent->parent->left->color == RED) {
currentCollisionNode->parent->color = BLACK;
currentCollisionNode->parent->parent->left->color = BLACK;
currentCollisionNode->parent->parent->color = RED;
currentCollisionNode = currentCollisionNode->parent->parent;
} else {
if (currentCollisionNode->parent->left == currentCollisionNode) {
//case 2 right rotation
pointerBrNode tmp = currentCollisionNode->right;
currentCollisionNode->parent->parent->right = currentCollisionNode;
currentCollisionNode->right = currentCollisionNode->parent;
currentCollisionNode->parent = currentCollisionNode->right->parent;
currentCollisionNode->right->parent = currentCollisionNode;
currentCollisionNode->right->left = tmp;
currentCollisionNode->right->left->parent = currentCollisionNode->right;
currentCollisionNode = currentCollisionNode->right;
} else {
//case 3 left rotation
pointerBrNode tmp = currentCollisionNode->parent->left;
currentCollisionNode->parent->left = currentCollisionNode->parent->parent;
if (currentCollisionNode->parent->parent==currentCollisionNode->parent->parent->parent->right) {
currentCollisionNode->parent->parent->parent->right = currentCollisionNode->parent;
} else {
currentCollisionNode->parent->parent->parent->left = currentCollisionNode->parent;
}
currentCollisionNode->parent->parent = currentCollisionNode->parent->parent->parent;
//currentCollisionNode->parent->parent->right写成了left;
//currentCollisionNode->parent->parent->left误写成了right
currentCollisionNode->parent->left->parent = currentCollisionNode->parent;
//currentCollisionNode->parent->parent->right误写成了left;
//currentCollisionNode->parent->parent->left误写成了right
currentCollisionNode->parent->left->right = tmp;
currentCollisionNode->parent->left->right->parent = currentCollisionNode->parent->left;
currentCollisionNode = currentCollisionNode->parent;
currentCollisionNode->color = BLACK;
currentCollisionNode->left->color = RED;
}
}
}
}
//currentCollisionNode->parent->parent == NULL 无法进入下面的if选择结构?
if (currentCollisionNode->parent->value < 0.0) {
root = currentCollisionNode;
root->color = BLACK;
if(root->parent->left != root)
root->parent->left = root;
if(root->parent->right != root)
root->parent->right = root;
}
}
void buildBrTree(float insertValue)
{
if (root == NULL){
root = constructNode(insertValue, NULL);
root->color = BLACK;
//construct parent of root in case that root parent is NULL pointer
pointerBrNode rootparent = (pointerBrNode)malloc(sizeof(pointerBrNode));
rootparent->parent = NULL;
rootparent->color = BLACK;
rootparent->left = root;
rootparent->right = root;
rootparent->value = NEGATIVEINFINITY;
rootparent->height = 0;
root->parent = rootparent;
return;
}
pointerBrNode tmp = root;
pointerBrNode parent = NULL;
while(tmp && tmp->value > 0.0) {
parent = tmp;
if (insertValue < tmp->value)
tmp = tmp->left;
else
tmp = tmp->right;
}
if (insertValue < parent->value) {
free(parent->left);
parent->left = constructNode(insertValue, parent);
adjust(parent->left);
} else {
free(parent->right);
parent->right = constructNode(insertValue, parent);
adjust(parent->right);
}
}
void inorder(pointerBrNode p2)
{
if (p2) {
inorder(p2->left);
if (p2->value > 0.0)
printf("(%f-%d) ", p2->value, p2->color);
inorder(p2->right);
}
}
void preorder(pointerBrNode p2)
{
if(p2) {
if (p2->value > 0.0)
printf("%f ", p2->value);
preorder(p2->left);
preorder(p2->right);
}
}
int main(int argv, char **argc)
{
float arr[LEN];
//6900.010254, 5054.184082, 5914.905273, \
5547.849121, 3784.288086,2577.321289, 2073.821289,\
6262.619141, 3401.270508, 8438.518555
//= {3.2, 9.7, 0.3, 6.7, 3.7, 0.6, 2.9, 8.8, 3.3, 0.9}
for (int i=0; i<LEN; i++)
arr[i] = (rand() * 1.0 / RAND_MAX)*10000;
int len = LEN;
//3.2, 9.7, 0.3, 6.7, 3.7, 0.6, 2.9, 8.8, 3.3, 0.9
while(len--) {
printf("%d %f\n", len, arr[len]);
buildBrTree(arr[len]);
}
inorder(root);
printf("\n");
preorder(root);
}
自己实现的红黑树的创建与可视化,记录在下面,以后可以过来更新。
虽然红黑树的创建部分还是有些bug,创建的二叉树并不满足红黑树的4大规则,可能对红黑树算法的理解还有偏差。但是其他功能模块都运行正常。代码包括以下功能模块:
1、创建二叉搜索树;
2、调整二叉搜索树为红黑树;
3、更新二叉树中每个节点的深度;
4、更新<=节点值节点数量;
5、计算二叉树的高度;
6、可视化二叉树(比较简陋);
7、前序遍历;
8、层次遍历;
9、中序遍历;
下面是代码部分:
#include <stdio.h>
#include <stdlib.h>
#define NEGATIVEINFINITY -1.0*RAND_MAX
#define LEN 40
#define max_t(type, x, y)({\
type __max1=(x);\
type __max2=(y);\
__max1 > __max2 ? __max1:__max2;})
enum COLOR {RED, BLACK};
//count: the number of element which is smaller than x
int count = 0;
typedef struct BRNODE{
COLOR color;
float value;
struct BRNODE *left;
struct BRNODE *right;
struct BRNODE *parent;
int height=0;
int smallerThanCurrentNode = -1;
}brNode, *pointerBrNode;
void inorder(pointerBrNode p2);
void preorder(pointerBrNode p2);
int heightOfTree(pointerBrNode p2);
pointerBrNode root = NULL;
pointerBrNode constructNode(float insertValue, pointerBrNode parent)
{
pointerBrNode p = (pointerBrNode)malloc(sizeof(brNode));
p->value = insertValue;
p->color = RED;
p->parent = parent;
//nil左子节点
p->left = (pointerBrNode)malloc(sizeof(brNode));
p->left->value = NEGATIVEINFINITY;
p->left->color = BLACK;
p->left->left = NULL;
p->left->right = NULL;
p->left->parent = p;
//nil右子节点
p->right = (pointerBrNode)malloc(sizeof(brNode));
p->right->value = NEGATIVEINFINITY;
p->right->color = BLACK;
p->right->left = NULL;
p->right->right = NULL;
p->right->parent = p;
return p;
}
void adjust(pointerBrNode currentCollisionNode)
{
//currentCollisionNode->parent->parent == NULL 容易出错
while(currentCollisionNode->parent->value > 0.0 && currentCollisionNode->color == RED) {
if (currentCollisionNode->parent->color == BLACK)
return;
if (currentCollisionNode->parent->parent->left == currentCollisionNode->parent) {
//case 1
if (currentCollisionNode->parent->parent->right->color == RED) {
currentCollisionNode->parent->color = BLACK;
currentCollisionNode->parent->parent->right->color = BLACK;
currentCollisionNode->parent->parent->color = RED;
currentCollisionNode = currentCollisionNode->parent->parent;
} else if (currentCollisionNode->parent->right == currentCollisionNode) {
//case 2 left rotation
pointerBrNode tmp = currentCollisionNode->left;
currentCollisionNode->parent->parent->left = currentCollisionNode;
currentCollisionNode->left = currentCollisionNode->parent;
currentCollisionNode->parent = currentCollisionNode->left->parent;
currentCollisionNode->left->parent = currentCollisionNode;
currentCollisionNode->left->right = tmp;
currentCollisionNode->left->right->parent = currentCollisionNode->left;
currentCollisionNode = currentCollisionNode->left;
//printf("when collision node is:%f, %f, %f\n", currentCollisionNode->value, currentCollisionNode->parent->value, currentCollisionNode->parent->parent->value);
} else {
//case 3 right rotation
//printf("case 3 inner %f\n", currentCollisionNode->value);
pointerBrNode tmp = currentCollisionNode->parent->right;
currentCollisionNode->parent->parent = currentCollisionNode->parent->parent->parent;
//currentCollisionNode->parent->parent->right写成了left;
currentCollisionNode->parent->right = currentCollisionNode->parent->parent->right;
currentCollisionNode->parent->right->parent = currentCollisionNode->parent;
//currentCollisionNode->parent->parent->right误写成了left;
currentCollisionNode->parent->parent->right = currentCollisionNode->parent;
currentCollisionNode->parent->right->left = tmp;
currentCollisionNode->parent->right->left->parent = currentCollisionNode->parent->right;
currentCollisionNode = currentCollisionNode->parent;
currentCollisionNode->color = BLACK;
currentCollisionNode->right->color = RED;
//printf("when collision node is:%d, %d, %d\n", currentCollisionNode->color, currentCollisionNode->left->color, currentCollisionNode->right->color);
}
} else {
if (currentCollisionNode->parent->parent->left->color == RED) {
currentCollisionNode->parent->color = BLACK;
currentCollisionNode->parent->parent->left->color = BLACK;
currentCollisionNode->parent->parent->color = RED;
currentCollisionNode = currentCollisionNode->parent->parent;
} else if (currentCollisionNode->parent->left == currentCollisionNode) {
//case 2 right rotation
pointerBrNode tmp = currentCollisionNode->right;
currentCollisionNode->parent->parent->right = currentCollisionNode;
currentCollisionNode->right = currentCollisionNode->parent;
currentCollisionNode->parent = currentCollisionNode->right->parent;
currentCollisionNode->right->parent = currentCollisionNode;
currentCollisionNode->right->left = tmp;
currentCollisionNode->right->left->parent = currentCollisionNode->right;
currentCollisionNode = currentCollisionNode->right;
//case 3 left rotation
} else {
pointerBrNode tmp = currentCollisionNode->parent->left;
currentCollisionNode->parent->parent = currentCollisionNode->parent->parent->parent;
//currentCollisionNode->parent->parent->left写成了right;
currentCollisionNode->parent->left = currentCollisionNode->parent->parent->left;
currentCollisionNode->parent->left->parent = currentCollisionNode->parent;
//currentCollisionNode->parent->parent->left误写成了right;
currentCollisionNode->parent->parent->left = currentCollisionNode->parent;
currentCollisionNode->parent->left->right = tmp;
currentCollisionNode->parent->left->right->parent = currentCollisionNode->parent->left;
currentCollisionNode = currentCollisionNode->parent;
currentCollisionNode->color = BLACK;
currentCollisionNode->left->color = RED;
}
}
}
//currentCollisionNode->parent->parent == NULL 无法进入下面的if选择结构?
if (currentCollisionNode->parent->value < 0.0) {
root = currentCollisionNode;
root->color = BLACK;
if(root->parent->left != root)
root->parent->left = root;
if(root->parent->right != root)
root->parent->right = root;
}
}
void buildBrTree(float insertValue)
{
if (root == NULL){
root = constructNode(insertValue, NULL);
root->color = BLACK;
//construct parent of root in case that root parent is NULL pointer
pointerBrNode rootparent = (pointerBrNode)malloc(sizeof(pointerBrNode));
rootparent->parent = NULL;
rootparent->color = BLACK;
rootparent->left = root;
rootparent->right = root;
rootparent->value = NEGATIVEINFINITY;
rootparent->height = 0;
root->parent = rootparent;
return;
}
pointerBrNode tmp = root;
pointerBrNode parent = NULL;
while(tmp && tmp->value > 0.0) {
parent = tmp;
if (insertValue < tmp->value)
tmp = tmp->left;
else
tmp = tmp->right;
}
if (insertValue < parent->value) {
free(parent->left);
parent->left = constructNode(insertValue, parent);
adjust(parent->left);
} else {
free(parent->right);
parent->right = constructNode(insertValue, parent);
adjust(parent->right);
}
}
//利用了前序遍历的优势;
void updateNodeDepth(pointerBrNode p2)
{
if (p2) {
p2->height = p2->parent->height + 1;
updateNodeDepth(p2->left);
updateNodeDepth(p2->right);
}
}
//通过一个全局变量统计之前访问过得元素个数
//很不错的想法
int smallerThanCurrentNode(pointerBrNode p2)
{
if (p2 && p2->value < 0)
return 0;
smallerThanCurrentNode(p2->left);
p2->smallerThanCurrentNode = count;
count++;
smallerThanCurrentNode(p2->right);
return 0;
}
int heightOfTree(pointerBrNode p2)
{
if (p2 && p2->value < 0)
return 0;
return max_t(int, heightOfTree(p2->left), heightOfTree(p2->right)) + 1;
}
void drawBinaryTree(pointerBrNode *p2, const int MAXDEPTH)
{
for (int depth = 1; depth < MAXDEPTH; depth++) {
pointerBrNode *tmp = p2;
//lastItemIndex用于记录前面已经打印过多少个-,
//增量打出-
int lastItemIndex = 0;
while(*tmp) {
if((*tmp)->height == depth) {
for(int i = 0; i<((*tmp)->smallerThanCurrentNode-lastItemIndex)*8;i++){
printf("-");
}
lastItemIndex = (*tmp)->smallerThanCurrentNode;
printf("%f",(*tmp)->value);
}
tmp++;
}
//不同深度打印在不同行
printf("\n");
}
}
void inorder(pointerBrNode p2)
{
if (p2) {
inorder(p2->left);
if (p2->value > 0.0)
printf("(%f-%d) ", p2->value, p2->color);
inorder(p2->right);
}
}
void preorder(pointerBrNode p2)
{
if(p2) {
if (p2->value > 0.0)
printf("%f ", p2->value);
preorder(p2->left);
preorder(p2->right);
}
}
pointerBrNode *hierarchyTraversal(pointerBrNode p2)
{
//如果没有static修饰,pointerBrNode在函数结束后会被释放。
//warning: address of local variable ‘ch’ returned [-Wreturn-local-addr]
static pointerBrNode brNodeArr[LEN];
brNodeArr[0] = p2;
int i = 0;
int j = 1;
while(i<j) {
//条件brNodeArr[i]->value>0,过滤到了叶子结点
//但是实际上,叶子结点加到数组了。当LEN=10时,i最后值是21。
//由于c语言不会进行数组越界检查,所以叶子几点仍可以加入
//原因是brNodeArr[i]->left->value>0
if(brNodeArr[i]->left && brNodeArr[i]->left->value>0) {
brNodeArr[j++] = brNodeArr[i]->left;
}
if(brNodeArr[i]->right && brNodeArr[i]->right->value>0)
brNodeArr[j++] = brNodeArr[i]->right;
i++;
}
printf("\ni is %d in hierarchyTraversal\n", i);
//brNodeArr[11] = root;
return brNodeArr;
}
int main(int argv, char **argc)
{
float arr[LEN];
//= {3.2, 9.7, 0.3, 6.7, 3.7, 0.6, 2.9, 8.8, 3.3, 0.9}
for (int i=0; i<LEN; i++)
arr[i] = (rand() * 1.0 / RAND_MAX)*10000;
int len = LEN;
//3.2, 9.7, 0.3, 6.7, 3.7, 0.6, 2.9, 8.8, 3.3, 0.9
while(len--) {
printf("%d %f\n", len, arr[len]);
buildBrTree(arr[len]);
}
//更新节点的深度
updateNodeDepth(root);
printf("%d", heightOfTree(root));
pointerBrNode *resultinhierarchyTraversal = hierarchyTraversal(root);
smallerThanCurrentNode(root);
drawBinaryTree(resultinhierarchyTraversal, heightOfTree(root));
//resultinhierarchyTraversal并不是指向(pointerBrNode *)数组,而是指向了root。
//下面循环的时候,实际上是在层次遍历整棵树,包括叶子结点。
/*
while(*resultinhierarchyTraversal) {
printf(" %f %d (%d)", (*resultinhierarchyTraversal)->value, (*resultinhierarchyTraversal)->height, \
(*resultinhierarchyTraversal)->smallerThanCurrentNode);
resultinhierarchyTraversal++;
}
*/
//drawBinaryTree(root, heightOfTree(root)-2);
//画二叉搜索树
printf("\n");
inorder(root);
//printf("\n");
//inorder(root);
}