分享红黑树代码(递归和迭代实现),含详细的注释,费尽心血整出来的,话说C语言的坑真多
程序代码:#include "redblacktree.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#define BLACK 0
#define RED 1
#define MAX_SIZE 50000
struct element{
int key;
};
struct treeNode{
treePointer leftChild;
element data;
short int color;
// int level;
treePointer rightChild;
treePointer parentp;
};
static treePointer *rootp;
typedef struct element element;
typedef struct treeNode *treePointer;
void InsertRedBlackNode(treePointer *grandp, treePointer *parent,
element *k); /* 插入节点操作 */
int LevelofRedBlackTree(treePointer T);/*计算树层高函数,采用层序遍历法 */
void preprintree(treePointer ptr); /* 前序查找打印 */
void LeftUnbalance(treePointer *grandp, treePointer *parent);/*处理左边不平衡*/
void RightUnbalance(treePointer *grandp, treePointer *parent);/*处理右边不平衡*/
void delRedBlackN(treePointer *root, element *k); /* 二叉查找树删除节点操作 */
void delFixup(treePointer delNode); //平衡调整
void leftRotate(treePointer node);
void rightRotate(treePointer node);
int main(void)
{
treePointer root = NULL;
element k;
int i;
rootp = &root;
int n, m[MAX_SIZE];
printf("请输入想要排序数据的数量:\n");
scanf("%d", &n);
assert(n < MAX_SIZE);
////////////////////////////////////////////////////////
srand(time(0)); //随机生成数据
for (i = 0; i < n; ++i){
m[i] = k.key = rand()%100000;
InsertRedBlackNode(NULL, &root, &k);
}
for(i = 0; i < n; ++i){
printf("\t%d", m[i]);
}
printf("\n");
preprintree(root);
system("pause");
// srand(time(0)); //随机生成数据
for (i = 0; i < n; ++i){
k.key = m[i];//rand()%100;
printf("del-%d-(第%d个) ", k.key, i+1);
delRedBlackN(&root, &k);
}
preprintree(root);
system("pause");
/*
for(i = 0; i < 4; i++){
printf("请输入您想要插入结点的值!\n");
scanf("%d", &k.key);
InsertRedBlackNode(NULL, &root, &k);
preprintree(root);
}
for(i = 0; i < 4; i++){
printf("请输入您想要删除结点的值!\n");
scanf("%d", &k.key);
delRedBlackN(&root, &k);
preprintree(root);
}
*/
}
void InsertRedBlackNode(treePointer *grandp, treePointer *parent,
element *k) /* 插入节点操作 */
{/* If K is in the tree pionted at by node do nothing; otherwise add
a new node with data = k */
if(!*parent){
*parent = (treePointer)malloc(sizeof(struct treeNode));
assert(*parent);
(*parent)->data.key = k->key;
(*parent)->leftChild = (*parent)->rightChild = NULL;
if(*parent == *rootp){ //can't be "parent == rootp", why?
(*parent)->color = BLACK;
(*parent)->parentp = NULL;
}else{
(*parent)->color = RED;
(*parent)->parentp = *grandp;
}
}else if(k->key < (*parent)->data.key){
InsertRedBlackNode(parent, &(*parent)->leftChild, k);
if((*parent)->color == RED && (*parent)->leftChild->color == RED)
LeftUnbalance(grandp, parent);
}else if(k->key > (*parent)->data.key){
InsertRedBlackNode(parent, &(*parent)->rightChild, k);
if((*parent)->color == RED && (*parent)->rightChild->color == RED)
RightUnbalance(grandp, parent);
}else{
printf("%d is already in the tree, can not be inserted!\n", k->key);
printf("Please insert another value!\n");
return ;
}
}
int LevelofRedBlackTree(treePointer T) /*计算树层高函数,采用层序遍历法 */
{
treePointer p = T, Q[MAX_SIZE];
int front = -1, rear = -1, last = 0, level = 0;
if(!T)
return 0;
Q[++rear] = p;
while(front < rear){
p = Q[++front];
if(p->leftChild)
Q[++rear] = p->leftChild;
if(p->rightChild)
Q[++rear] = p->rightChild;
if(front == last){
last = rear;
level++; //层次+1
}
}
return level;
}
void preprintree(treePointer ptr)
{
if(ptr == NULL){ /* 为空树则返回 */
printf("此树为空!\n");
return ;
}
printf("节点%d:color is %d; lchild is %p;rtchild is %p;parent is %d.\n",
ptr->data.key, ptr->color, ptr->leftChild, ptr->rightChild,
(ptr->parentp == NULL ? 0 : ptr->parentp->data.key));
if(ptr->leftChild != NULL)
preprintree(ptr->leftChild);
if(ptr->rightChild != NULL)
preprintree(ptr->rightChild);
}
void LeftUnbalance(treePointer *grandp, treePointer *parent) //左边不平衡
{
treePointer tempg, tempp, temps;
if(parent == &(*grandp)->leftChild /* LLr不平衡 */
&& (*grandp)->rightChild != NULL && (*grandp)->rightChild->color == RED)
{//牢记:必须先判断是否为真,否则可能尝试读取空址值,程序就会出错
printf("LLr:OK\n");
if(rootp == grandp){
(*grandp)->rightChild->color = BLACK;
(*parent)->color = BLACK;
}else{
(*grandp)->color = RED;
(*grandp)->rightChild->color = BLACK;
(*parent)->color = BLACK;
}
}else if(parent == &(*grandp)->leftChild /* LLb不平衡,需要旋转 */
&& (*grandp)->rightChild == NULL || (*grandp)->rightChild->color == BLACK){
printf("LLb:OK\n");
tempg = *grandp; tempg->color = RED;
tempp = *parent; tempp->color = BLACK;
tempg->leftChild = (*parent)->rightChild;
if(tempp->rightChild) //连接父结点
tempp->rightChild->parentp = tempg;
tempp->parentp = tempg->parentp;
tempg->parentp = tempp;
*grandp = tempp;
(*grandp)->rightChild = tempg;
}else if(parent == &(*grandp)->rightChild /* RLr不平衡 */
&& (*grandp)->leftChild != NULL && (*grandp)->leftChild->color == RED){
printf("RLr:OK\n");
if(rootp == grandp){
(*grandp)->leftChild->color = BLACK;
(*parent)->color = BLACK;
}else{
(*grandp)->color = RED;
(*grandp)->leftChild->color = BLACK;
(*parent)->color = BLACK;
}
}else if(parent == &(*grandp)->rightChild /* RLb不平衡,需要旋转 */
&& (*grandp)->leftChild == NULL || (*grandp)->leftChild->color == BLACK){
printf("RLb:OK\n");
tempg = *grandp; //保存祖结点
tempp = *parent; //保存父结点
tempg->rightChild = (*parent)->leftChild->leftChild;
tempg->color = RED;
temps = tempp->leftChild; //保存子结点
temps->parentp = tempg->parentp;
if(temps->leftChild)
temps->leftChild->parentp = tempg;
if(temps->rightChild)
temps->rightChild->parentp = tempp;
tempp->parentp = tempp->leftChild;
tempg->parentp = tempp->leftChild;
tempp->leftChild = temps->rightChild;
temps->rightChild = tempp;
temps->leftChild = tempg;
temps->color = BLACK;
*grandp = temps;
}
}
void RightUnbalance(treePointer *grandp, treePointer *parent)//右边不平衡
{
treePointer tempg, tempp, temps;
if(parent == &(*grandp)->leftChild /* LRb不平衡,需要旋转 */
&& (*grandp)->rightChild == NULL || (*grandp)->rightChild->color == BLACK)
{//牢记:必须先判断是否为空,否则先读取空址值,程序就会出错
printf("LRb:OK\n");
tempg = *grandp; //保存祖结点
tempp = *parent; //保存父结点
tempg->leftChild = (*parent)->rightChild->rightChild;
tempg->color = RED; //不知道为什么上行代码执行后*parent会变成NULL。
temps = tempp->rightChild; //保存子结点
temps->parentp = tempg->parentp; //连接父结点
if(temps->leftChild)
temps->leftChild->parentp = tempp;
if(temps->rightChild)
temps->rightChild->parentp = tempg;
tempp->parentp = tempp->rightChild;
tempg->parentp = tempp->rightChild;
tempp->rightChild = temps->leftChild;
temps->leftChild = tempp;
temps->rightChild = tempg;
temps->color = BLACK;
*grandp = temps;
}else if(parent == &(*grandp)->leftChild /* LRr不平衡 */
&&(*grandp)->rightChild != NULL &&(*grandp)->rightChild->color==RED){
printf("LRr:OK\n");
if(rootp == grandp){
(*grandp)->rightChild->color = BLACK;
(*parent)->color = BLACK;
}else{
(*grandp)->color = RED;
(*grandp)->rightChild->color = BLACK;
(*parent)->color = BLACK;
}
}else if(parent == &(*grandp)->rightChild /* RRb不平衡,需要旋转 */
&& ((*grandp)->leftChild == NULL || (*grandp)->leftChild->color == BLACK)){
printf("RRb:OK\n");
tempg = *grandp; tempg->color = RED;
tempp = *parent; tempp->color = BLACK;
tempg->rightChild = (*parent)->leftChild;
//为什么上面这行代码执行完后中,*parent的值会变为NULL呢?
if(tempp->leftChild) //连接父结点
tempp->leftChild->parentp = tempg;
tempp->parentp = tempg->parentp;
tempg->parentp = tempp;
*grandp = tempp;
(*grandp)->leftChild = tempg;
}else if(parent == &(*grandp)->rightChild /* RRr不平衡 */
&&(*grandp)->leftChild != NULL && (*grandp)->leftChild->color == RED){
printf("RRr:OK\n");
if(rootp == grandp){
(*grandp)->leftChild->color = BLACK;
(*parent)->color = BLACK;
}else{
(*grandp)->color = RED;
(*grandp)->leftChild->color = BLACK;
(*parent)->color = BLACK;
}
}
}
/*学习借鉴了网上《一篇不错的红黑树代码》一文,该文对红黑树的算法有图文介绍 */
void delFixup(treePointer delposition)
{
assert(delposition);
treePointer p = delposition;
while (p != *rootp && p->color == BLACK) {
if (p->parentp->leftChild && p == p->parentp->leftChild) {//删除节点在左子树
treePointer sibling = p->parentp->rightChild;//sibling英文含义为兄弟
if (sibling && sibling->color == RED) { //右兄为红
sibling->color = BLACK;
p->parentp->color = RED;
printf("lrotate->1\t\n");
leftRotate(p->parentp);
sibling = p->parentp->rightChild;
}
//右兄为不为红且二子为黑
if ((!sibling->leftChild ||sibling->leftChild->color == BLACK)
&& (!sibling->rightChild ||sibling->rightChild->color == BLACK)){
sibling->color = RED;
p = p->parentp;
}else {//剩余情况:右兄不为红且二子不全黑
if(!sibling->rightChild || sibling->rightChild->color == BLACK){//右兄右子为黑(左子红)
sibling->leftChild->color = BLACK;
sibling->color = RED;
printf("rrotate->1\t\n");
rightRotate(sibling);
sibling = sibling->parentp;
}
//只剩下一种情况:右兄左子黑右子红
sibling->color = sibling->parentp->color;
sibling->parentp->color = BLACK;
sibling->rightChild->color = BLACK;
printf("lrotate->2\t\n");
leftRotate(sibling->parentp);
p = *rootp;
}
}else{//删除节点在右子树
treePointer sibling = p->parentp->leftChild;
/*
printf("sibling color is %d, p->parent is %d, p->parent->lchild is %d\n",
sibling->color, p->parentp->leftChild->data.key, p->parentp->data.key);*/
if(sibling && (sibling->color == RED)){ //左兄为红
sibling->color = BLACK;
p->parentp->color = RED;
rightRotate(p->parentp);
printf("rrotate->2\t\n");
sibling = p->parentp->leftChild;
}
//左兄为不为红且二子皆黑
if ((!sibling->leftChild || sibling->leftChild->color == BLACK)
&& (!sibling->rightChild || sibling->rightChild->color == BLACK)){
sibling->color = RED;
p = p->parentp;
}else {//剩余情况:左兄不为红且二子不全黑
if (!sibling->leftChild || sibling->leftChild->color == BLACK) {
sibling->rightChild->color = BLACK;
sibling->color = RED;
printf("lrotate->3\t\n");
leftRotate(sibling);
sibling = sibling->parentp;
/*
printf("sibling %d, p is %d,grandp is %d\n",
sibling->data.key, sibling->parentp->data.key,
sibling->parentp->parentp->data.key);
*/ }
//只剩下一种情况:左兄右子黑左子红
sibling->color = sibling->parentp->color;
sibling->parentp->color = BLACK;
sibling->leftChild->color = BLACK;
printf("rrotate->3\t\n");
rightRotate(sibling->parentp);
p = *rootp;
}
}
}
p->color = BLACK;
}
void leftRotate(treePointer node)
{ //把一个节点向左下方移一格,并让他原来的右子节点代替它的位置。
assert(node);
treePointer right = node->rightChild;
treePointer temp = node->parentp;
node->rightChild = right->leftChild;
if(node->rightChild)
node->rightChild->parentp = node;
if(node->parentp == NULL){
*rootp = right;
}else if (node == node->parentp->leftChild) {
node->parentp->leftChild = right;
}else{
node->parentp->rightChild = right;
}
right->parentp = temp;
right->leftChild = node;
node->parentp = right;
}
void rightRotate(treePointer node)
{ //把一个节点向右下方移一格,并让他原来的左子节点代替它的位置。
assert(node);
treePointer left = node->leftChild;
treePointer temp = node->parentp;
node->leftChild = left->rightChild;
if(node->leftChild)
node->leftChild->parentp = node;
if(node->parentp == NULL){
*rootp = left;
}else if(node == node->parentp->leftChild){
node->parentp->leftChild = left;
}else{
node->parentp->rightChild = left;
}
left->parentp = temp;
left->rightChild = node;
node->parentp = left;
printf("rrotate is ok\n");
}
void delRedBlackN(treePointer *root, element *k) /* 二叉查找树删除节点操作 */
{
treePointer parent = NULL; /* parent:记录父节点 */
treePointer pcur = *root; /* pcur:记录当前节点 */
treePointer del = pcur; /* del:记录需要删除的节点 */
int color;
if(pcur->data.key == k->key && pcur == *root &&
(!pcur->leftChild || !pcur->rightChild)){
if(!pcur->leftChild && !pcur->rightChild){//根结点无孩,直接删除之。
*root = NULL;
}else{ //根结点有一孩
if(pcur->leftChild){
pcur->leftChild->color = BLACK;
*root = pcur->leftChild;
(*root)->parentp = NULL;
}else{
pcur->rightChild->color = BLACK;
*root = pcur->rightChild;
(*root)->parentp = NULL;
}
}
free(pcur);
return;
}
while(pcur){ /* 不断循环,下移一层,
直到找到要删除的节点,或直到为空*/
if(pcur->data.key > k->key){
parent = pcur;
pcur = pcur->leftChild;
}else if(pcur->data.key < k->key ){
parent = pcur;
pcur = pcur->rightChild;
}else{ /* 找要删除的值,pcur即指向该节点,接着进行下一步处理 */
treePointer replace;
if(!pcur->leftChild || !pcur->rightChild ){ //pcur无孩或有1孩
if(pcur->color == RED){//删除节点 为红
if(pcur == pcur->parentp->leftChild)
pcur->parentp->leftChild =
pcur->leftChild ? pcur->leftChild : pcur->rightChild;
else
pcur->parentp->rightChild =
pcur->leftChild ? pcur->leftChild : pcur->rightChild;
}else{ //删除的是黑结点
replace = pcur->leftChild ? pcur->leftChild : pcur->rightChild;
if(replace && replace->color == RED){ //替换删除结点的为红
if(pcur == pcur->parentp->leftChild){
pcur->parentp->leftChild = replace;
replace->parentp = pcur->parentp;
replace->color = BLACK;
}else{
pcur->parentp->rightChild = replace;
replace->parentp = pcur->parentp;
replace->color = BLACK;
}
}else{//替换删除结点的为黑
printf("delFixup->\t\n");
delFixup(pcur);
if(pcur == pcur->parentp->leftChild){
pcur->parentp->leftChild = replace;
if(replace)
replace->parentp = pcur->parentp;
}else{
pcur->parentp->rightChild = replace;
if(replace)
replace->parentp = pcur->parentp;
}
}
}
free(pcur);
return;
}else{//pcur有2孩
treePointer left = pcur->rightChild; //left为右子树最左值
treePointer precur = pcur; /* precur:记录前节点 */
treePointer tempr, templ, tempp;
while(left->leftChild){ /*循环查找右子树中的最小值 */
precur = left;
left = left->leftChild;
}
//交换节点pcur与left的值,这里很关键.
if(left == pcur->rightChild){ //这种情况为右子树根无左孩
//以下把left与pcur结点互换
color = left->color;
tempr = left->rightChild;
templ = left->leftChild;
tempp = pcur->parentp;;
left->color = precur->color;
left->leftChild = precur->leftChild;//设置左指针
left->leftChild->parentp = left;
left->rightChild = precur;//设置右指针
left->rightChild->parentp = left;//注意:这一行代码更改了pcur->parentp的值!!!!
if(pcur == *rootp){//设置父指针
left->parentp = NULL;
}else{
left->parentp = parent;//为什么不能为pcur->parentp???
}
if(parent && pcur == parent->leftChild){
parent->leftChild = left;
}else if(parent && pcur == parent->rightChild){
parent->rightChild = left;
}else{
*rootp = left;
}
//设置pcur
pcur->parentp = left;
pcur->rightChild = tempr;
if(pcur->rightChild)
pcur->rightChild->parentp = pcur;
pcur->color = color;
pcur->leftChild = templ;
if(pcur->leftChild)
pcur->leftChild->parentp = pcur;
//重新一轮迭代,引导至删除操作
continue;
}else{
color = left->color;
tempr = left->rightChild;
templ = left->leftChild;
left->color = pcur->color;
left->leftChild = pcur->leftChild;//设置左指针
if(left->leftChild)
left->leftChild->parentp = left;
left->rightChild = pcur->rightChild;//设置右指针
if(left->rightChild)
left->rightChild->parentp = left;
left->parentp = parent;//设置父指针
if(parent && pcur == parent->leftChild){
parent->leftChild = left;
}else if(parent && pcur == parent->rightChild){
parent->rightChild = left;
}else{
*root = left;
}
//设置pcur
precur->leftChild = pcur;
pcur->parentp = precur;
pcur->rightChild = tempr;//设置右指针
if(pcur->rightChild)
pcur->rightChild->parentp = pcur;
pcur->color = color;
pcur->leftChild = templ;//设置左指针
if(pcur->leftChild)
pcur->leftChild->parentp = pcur;
//重新一轮迭代,引导至删除操作
continue;
}
}
}
}
if(pcur == NULL)/* 说明没找删除的值 */
printf("没找到您要删除的值!\n") ;
}










