标题:分享红黑树代码(递归和迭代实现),含详细的注释,费尽心血整出来的,话说 ...
只看楼主
marlow
Rank: 6Rank: 6
等 级:侠之大者
威 望:2
帖 子:125
专家分:419
注 册:2016-7-18
结帖率:75%
已结贴  问题点数:100 回复次数:5 
分享红黑树代码(递归和迭代实现),含详细的注释,费尽心血整出来的,话说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") ;
}

搜索更多相关主题的帖子: RED BLACK color parent printf 
2017-08-17 19:54
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
得分:34 
这个要顶~
感觉红黑树的难点就是要对删除节点的情况进行合并整理,那里的代码信息量感觉较大~

[此贴子已经被作者于2017-8-18 06:43编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-08-18 06:31
marlow
Rank: 6Rank: 6
等 级:侠之大者
威 望:2
帖 子:125
专家分:419
注 册:2016-7-18
得分:0 
回复 2楼 九转星河
删除函数代码比较多主要是在交换两个结点(我不愿采用a.key = b.key,b.key = a.key这种方法),交换后要重新与旁边的结点连接起来,处理起来比较棘手。红黑树删除的难点在与理解删除算法的逻辑。而我遇到最大的困难在于感觉C语言很难驾驭,一是不容许出一丁点的错误,二是经常出现一些难以解释的问题。欢迎大家来交流

一切都在学习、尝试、摸索中
2017-08-18 08:44
renkejun1942
Rank: 14Rank: 14Rank: 14Rank: 14
来 自:不是这样
等 级:贵宾
威 望:33
帖 子:1645
专家分:5297
注 册:2016-12-1
得分:34 
还没学到红黑树,先收藏。

09:30 05/21 种下琵琶种子,能种活么?等待中……
21:50 05/27 没有发芽。
20:51 05/28 没有发芽。
23:03 05/29 没有发芽。
23:30 06/09 我有预感,要发芽了。
2017-08-19 08:34
Zhigeng
Rank: 2
等 级:论坛游民
帖 子:2
专家分:34
注 册:2017-8-23
得分:34 
谢谢分享 楼主辛苦了!
2017-08-23 10:47
没错就是我
Rank: 1
等 级:新手上路
帖 子:1
专家分:0
注 册:2018-5-4
得分:0 
回复 楼主 marlow
话说redblacktree.h在哪有
2018-05-04 19:39



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-480131-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.163345 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved