紅黑樹純C語言實現,參考算法導論,已驗證

說起紅黑樹,最頭疼的就是插入或刪除後引起的不平衡,各種旋轉,着色細節讓人難以理解。我一開始是網上找別人的代碼來看,看的一頭霧水,還是算法導論上的的僞代碼到位,不用糾結於各種細節,雖然我現在依然沒有徹底搞清楚,但是根據書上的僞代碼寫了一遍,居然也能通過驗證。

這裏不做深入分析,只要對紅黑樹有個大概的瞭解,相信書上的算法就好。對插入和刪除要做哪些事情大體瞭解下,不用探究細節。不廢話,直接上代碼,我的一些理解寫在了代碼註釋中

更新一下,刪除節點在remove_rbt_node方法末尾,在執行待刪除節點與他右子樹最左邊的節點交換後,調用free,這點算法導論書上沒有寫出

調試中輸出了涉及旋轉、交換的節點的值,直觀的感受插入和刪除操作的過程

頭文件

/* 
 * File:   rb_tree.h
 * Author: weng
 *
 * Created on 2018年11月8日, 下午9:40
 */

#ifndef RB_TREE_H
#define RB_TREE_H

#ifdef __cplusplus
extern "C" {
#endif

#define DEBUG_RBT 1

    typedef int RBTKey;

    enum rbt_color {
        RED = 0, BLACK
    };

    struct rbt_node {
        struct rbt_node* parent;
        struct rbt_node* left;
        struct rbt_node* right;
        RBTKey key;
        enum rbt_color color;
    };

    struct rb_tree {
        struct rbt_node* root;
        struct rbt_node* nil;
    };

    typedef struct rbt_node RBTNode;
    typedef struct rb_tree RBTree;

    /*
     * 常用方法
     */
    RBTree* create_rbtree(void); //使用malloc在堆中創建紅黑樹並初始化
    RBTree* init_rbtree(RBTree* t); //初始化
    RBTree* insert_rbt_node(RBTree* t, const RBTKey key); //插入key
    RBTree* remove_rbt_node(RBTree* t, const RBTKey key); //刪除key對應節點
    void clear_rbtree(RBTree* t); //後序遍歷,free樹中的節點,對於t需要另行處理
    void display_rbt(RBTree* t); //中序遍歷
    void display_rbt_prevorder(RBTree* t); //先序遍歷
    void display_rbt_postorder(RBTree* t); //後序遍歷
    void show_rbt(RBTree* t); //圖示




    /*
     * 輔助函數
     * 參數中RBTree* t, RBTNode* r
     * t->root爲根節點, r爲待操作的節點
     */
    RBTNode* create_rbt_node(const RBTKey key); //使用malloc在堆中創建節點並初始化

    RBTree* rbt_insert_fixup(RBTree* t, RBTNode* r); //插入後平衡

    RBTree* rbt_left_rotate(RBTree* t, RBTNode* r); //左旋
    RBTree* rbt_right_rotate(RBTree* t, RBTNode* r); //右旋

    RBTree* rbt_transplant(RBTree* t, RBTNode* u, RBTNode* v); //互換節點
    RBTree* rbt_delete_fixup(RBTree* t, RBTNode* r); //刪除後平衡
    RBTNode* rbt_minimum(RBTree* t, RBTNode* r); //返回將與待刪除節點互換的節點 \
    //這裏是用待刪除節點的右孩子的最左邊一個節點與待刪除節點互換,使得他們位置變換, \
    //然後執行刪除,這樣樹的整體結構不變,之後執行平衡策略

    void clear_rbt_node_post(RBTree* t, RBTNode* r);

    void display_rbt_node(RBTree* t, RBTNode* r);
    void display_rbt_node_prev(RBTree* t, RBTNode* r);
    void display_rbt_node_post(RBTree* t, RBTNode* r);
    void show_rbt_node(RBTree* t, RBTNode* r, int high, int n); //



#ifdef __cplusplus
}
#endif

#endif /* RB_TREE_H */

方法實現源文件

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
#include "rb_tree.h"
#include <stdio.h>
#include <stdlib.h>

RBTree* create_rbtree(void) {
    RBTree* t = (RBTree*) malloc(sizeof (RBTree));
    /*
        t->nil = create_rbt_node(0);
        t->nil->color = BLACK;
        t->root = t->nil;
        return t;
     */
    init_rbtree(t);
    return t;
}

RBTree* init_rbtree(RBTree* t) {
    t->nil = create_rbt_node(0);
    t->nil->color = BLACK;
    t->root = t->nil;
    return t;
}

RBTree* insert_rbt_node(RBTree* t, const RBTKey key) {
    RBTNode* rp = t->root; //插入路徑上的迭代器//書上記作x
    RBTNode* parent = t->nil; //迭代器的父節點//y
    /*
        RBTNode* r = create_rbt_node(key); //待插入的節點//z
     */
    while (rp != t->nil) {
        parent = rp;
        if (key < rp->key)
            rp = rp->left;
        else if (key > rp->key)
            rp = rp->right;
        else
            return t; //樹中已有key,返回
    }

    RBTNode* r = create_rbt_node(key); //待插入的節點//z
    r->parent = parent;
    r->left = t->nil;
    r->right = t->nil;

    if (parent == t->nil)
        t->root = r;
    else if (key < parent->key)
        parent->left = r;
    else
        parent->right = r;

    t = rbt_insert_fixup(t, r);
    return t;
}

RBTree* remove_rbt_node(RBTree* t, const RBTKey key) {
    RBTNode* rp = t->root; //刪除路徑上的迭代器//y
    while (rp != t->nil) {
        if (key < rp->key)
            rp = rp->left;
        else if (key > rp->key)
            rp = rp->right;
        else
            break; //找到key
    }
    if (rp == t->nil)
        return t; //未找到

    RBTNode* z = rp; //z 待刪除key的節點
    enum rbt_color y_o_c = rp->color; //記錄顏色
    RBTNode* x; //記錄z的孩子節點

    if (z->left == t->nil) {
        x = z->right;
        rbt_transplant(t, z, z->right);
    } else if (z->right == t->nil) {
        x = z->left;
        rbt_transplant(t, z, z->left);
    } else {
        rp = rbt_minimum(t, z->right);

        /*
                //以下4行爲tree_minimum方法
                rp = z->right;
                while (rp->left != t->nil) {
                    rp = rp->left;
                }
         */

        y_o_c = rp->color;
        x = rp->right;
        if (rp->parent == z)
            x->parent = rp;
        else {
            rbt_transplant(t, rp, rp->right);
            rp->right = z->right;
            rp->right->parent = rp;
        }
        rbt_transplant(t, z, rp);
        rp->left = z->left;
        rp->left->parent = rp;
        rp->color = z->color;
    }

#ifdef DEBUG_RBT
        printf("刪除節點 %d\n", u->key);
#endif
    free(z);//刪除節點

    if (y_o_c == BLACK)
        rbt_delete_fixup(t, x);
}

void clear_rbtree(RBTree* t) {
    if (t == NULL)return;
    clear_rbt_node_post(t, t->root);
    if (t->nil != NULL)
        free(t->nil);
}

void display_rbt(RBTree* t) {
    if (t == NULL)return;
    display_rbt_node(t, t->root);
    printf("\n");
}

void display_rbt_prevorder(RBTree* t) {
    if (t == NULL)return;
    display_rbt_node_prev(t, t->root);
    printf("\n");
}

void display_rbt_postorder(RBTree* t) {
    if (t == NULL)return;
    display_rbt_node_post(t, t->root);
    printf("\n");
}

void show_rbt(RBTree* t) {
    if (t == NULL)return;
    int h = 0;
    int n = 0;
    show_rbt_node(t, t->root, h, n);
}

RBTNode* create_rbt_node(const RBTKey key) {
    RBTNode* r = (RBTNode*) malloc(sizeof (RBTNode));
    r->left = r->right = r->parent = NULL;
    r->color = RED;
    r->key = key;
    return r;
}

/*
 * 參數中RBTree* t, RBTNode* r
 * t->root爲根節點, r爲待操作的節點
 */
RBTree* rbt_insert_fixup(RBTree* t, RBTNode* r) {
    while (r->parent->color == RED) {
        if (r->parent == r->parent->parent->left) {
            RBTNode* u = r->parent->parent->right; //r的叔叔uncle;//y
            if (u->color == RED) {//case 1
                r->parent->color = BLACK;
                u->color = BLACK;
                r->parent->parent->color = RED;
                r = r->parent->parent;
            } else if (r == r->parent->right) {//case 2
                r = r->parent;
                rbt_left_rotate(t, r);
            } else {//case 3//第三版書上這裏沒有else,加上
                r->parent->color = BLACK;
                r->parent->parent->color = RED;
                rbt_right_rotate(t, r->parent->parent);
            }
        } else {
            RBTNode* u = r->parent->parent->left; //r的叔叔uncle;//y
            if (u->color == RED) {
                r->parent->color = BLACK;
                u->color = BLACK;
                r->parent->parent->color = RED;
                r = r->parent->parent;
            } else if (r == r->parent->left) {
                r = r->parent;
                rbt_right_rotate(t, r);
            } else {//
                r->parent->color = BLACK;
                r->parent->parent->color = RED;
                rbt_left_rotate(t, r->parent->parent);
            }
        }
    }//while

    t->root->color = BLACK;
    return t;
}

RBTree* rbt_left_rotate(RBTree* t, RBTNode* r) {
    if (r->right != t->nil) {
        RBTNode* child = r->right; //y
#ifdef DEBUG_RBT
        printf("left_rolate %d<->%d\n", r->key, child->key);
#endif
        r->right = child->left;
        if (child->left != t->nil)
            child->left->parent = r;
        child->parent = r->parent;
        if (r->parent == t->nil)
            t->root = child;
        else if (r == r->parent->left)
            r->parent->left = child;
        else
            r->parent->right = child;
        child->left = r;
        r->parent = child;
    }

    return t;
}

RBTree* rbt_right_rotate(RBTree* t, RBTNode* r) {
    if (r->left != t->nil) {//書上僞代碼之前假設這個條件,
        //根節點的父節點爲nil已經在init_rbtree()方法中初始化
        RBTNode* child = r->left; //y
#ifdef DEBUG_RBT
        printf("right_rolate %d<->%d\n", r->key, child->key);
#endif
        r->left = child->right;
        if (child->right != t->nil)
            child->right->parent = r;
        child->parent = r->parent;
        if (r->parent == t->nil)
            t->root = child;
        else if (r == r->parent->right)
            r->parent->right = child;
        else
            r->parent->left = child;
        child->right = r;
        r->parent = child;
    }

    return t;
}

RBTree* rbt_transplant(RBTree* t, RBTNode* u, RBTNode* v) {
    if (u->parent == t->nil)
        t->root = v;
    else if (u == u->parent->left)
        u->parent->left = v;
    else
        u->parent->right = v;
    v->parent = u->parent;
#ifdef DEBUG_RBT
        printf("transplant %d %d\n", u->key, v->key);
#endif
    return t;
}

RBTree* rbt_delete_fixup(RBTree* t, RBTNode* x) {//r=x
    while (x != t->root && x->color == BLACK) {
        RBTNode* w; //記錄x的兄弟節點
        if (x == x->parent->left) {
            w = x->parent->right;
            if (w->color == RED) {//case 1
                w->color = BLACK;
                x->parent->color = RED;
                rbt_left_rotate(t, x->parent);
                w = x->parent->right;
            }
            if (w->left->color == BLACK && w->right->color == BLACK) {//case 2
                w->color = RED;
                x = x->parent;
            } else if (w->right->color == BLACK) {//case 3
                w->left->color = BLACK;
                w->color = RED;
                rbt_right_rotate(t, w);
                w = x->parent->right;
            } else {//else一定要加上//case 4
                w->color = x->parent->color; //case 4
                x->parent->color = BLACK;
                w->right->color = BLACK;
                rbt_left_rotate(t, x->parent);
                x = t->root;
            }
        } else {//鏡像
            w = x->parent->left;
            if (w->color == RED) {//case 1
                w->color = BLACK;
                x->parent->color = RED;
                rbt_right_rotate(t, x->parent);
                w = x->parent->left;
            }
            if (w->right->color == BLACK && w->left->color == BLACK) {//case 2
                w->color = RED;
                x = x->parent;
            } else if (w->left->color == BLACK) {//case 3
                w->right->color = BLACK;
                w->color = RED;
                rbt_left_rotate(t, w);
                w = x->parent->left;
            } else {
                w->color = x->parent->color; //case 4
                x->parent->color = BLACK;
                w->left->color = BLACK;
                rbt_right_rotate(t, x->parent);
                x = t->root;
            }
        }
    }//while

    x->color = BLACK;
}

RBTNode* rbt_minimum(RBTree* t, RBTNode* r) {
    while (r->left != t->nil) {
        r = r->left;
    }
    return r;
}

void clear_rbt_node_post(RBTree* t, RBTNode* r) {
    if (r != t->nil) {
        clear_rbt_node_post(t, r->left);
        clear_rbt_node_post(t, r->right);
        if (r != NULL)
            free(r);
    }
}

void display_rbt_node(RBTree* t, RBTNode* r) {
    if (r != t->nil) {
        display_rbt_node(t, r->left);
        /*
                printf("%d\n", r->key);
         */
        printf("%d ", r->key);
        display_rbt_node(t, r->right);
    }
}

void display_rbt_node_prev(RBTree* t, RBTNode* r) {
    if (r != t->nil) {
        /*
                printf("%d\n", r->key);
         */
        printf("%d ", r->key);
        display_rbt_node_prev(t, r->left);
        display_rbt_node_prev(t, r->right);
    }
}

void display_rbt_node_post(RBTree* t, RBTNode* r) {
    if (r != t->nil) {
        display_rbt_node_post(t, r->left);
        display_rbt_node_post(t, r->right);
        /*
                printf("%d\n", r->key);
         */
        printf("%d ", r->key);
    }
}

void show_rbt_node(RBTree* t, RBTNode* r, int high, int n) {
    if (r != t->nil) {
        show_rbt_node(t, r->right, high + 7, n + 1);
        int i = 0;
        while (i != high) {
            if (i % 7 == 0) {
                if (i >= 7 * n)
                    printf("|");
                else
                    printf(" ");
            } else
                printf(" ");
            i++;
        }
        if (r->color == RED)
            printf("|-<R>");
        else printf("|-<B>");
        printf("%2d-\n", r->key);

        show_rbt_node(t, r->left, high + 7, n + 1);
    } else {
        int i = 0;
        while (i != high) {
            if (i % 7 == 0) {
                if (i >= 7 * n)
                    printf("|");
                else
                    printf(" ");
            } else
                printf(" ");
            i++;
        }
        printf("|-NIL\n");
    }
}

測試程序main.c,用隨機數進行插入、刪除測試,多次測試沒有問題

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/* 
 * File:   main.c
 * Author: weng
 *
 * Created on 2018年11月8日, 下午9:39
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "rb_tree.h"

/*
 * 
 */
#define N_NODES 50
#define ARRAYSIZE 100001

int main(int argc, char** argv) {
    int i, n = 0;
    srand(time(0));
    int array[ARRAYSIZE];
    memset(array, -1, sizeof (array));

    RBTree* t = create_rbtree();
    for (i = 0; i < N_NODES; i++) {
        int num = rand() % N_NODES;
        insert_rbt_node(t, num);

        /*
                num = i;
                insert_rbt_node(t, num);
         */

        if (num != array[num]) {
            printf("插入: %d \n", num);
            array[num] = num;
            n++;
        } else {
            printf("重複插入 %d\n", num);
        }
    }
    printf("array: \n");
    for (int i = 0; i < ARRAYSIZE; i++)
        if (array[i] != -1)
            printf("%d ", array[i]);
    printf("\nhow many: %d\n", n);
    printf("display: \n");
    display_rbt(t);
    display_rbt_prevorder(t);
    display_rbt_postorder(t);

    show_rbt(t);

    for (i = 0; i < N_NODES; i++) {
        int num = rand() % N_NODES;
        remove_rbt_node(t, num);

        /*
                num = i;
                remove_rbt_node(t, num);
         */

        if (num == array[num]) {
            printf("刪除: %d \n", num);
            array[num] = -1;
            n--;
        } else {
            printf("重複刪除或不存在 %d\n", num);
        }
    }
   
    show_rbt(t);
    printf("array: \n");
    for (int i = 0; i < ARRAYSIZE; i++)
        if (array[i] != -1)
            printf("%d ", array[i]);
    printf("\nhow many: %d\n", n);
    printf("display: \n");
    display_rbt(t);
    display_rbt_prevorder(t);
    display_rbt_postorder(t);

    clear_rbtree(t);
    free(t);

    return (EXIT_SUCCESS);
}

這是隨機插入20次並刪除20次的整個過程

其他幾次測試結果圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章