`

红黑树(Red-Black Tree)不在话下

阅读更多

红黑树(Red-Black Tree)

红黑树定义

红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:

    性质1. 节点是红色或黑色。

    性质2. 根是黑色。

    性质3. 所有叶子都是黑色(叶子是NIL节点)。

    性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)

    性质5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。

An example of a red-black tree

 

下面先给出红黑树的抽象数据类型

 

#ifndef RBT_H
#define RBT_H

typedef enum {
    RBT_STATUS_OK,
    RBT_STATUS_MEM_EXHAUSTED,
    RBT_STATUS_DUPLICATE_KEY,
    RBT_STATUS_KEY_NOT_FOUND
} RbtStatus;

typedef void *RbtIterator;
typedef void *RbtHandle;

RbtHandle rbtNew(int(*compare)(void *a, void *b));
// create red-black tree
// parameters:
//     compare  pointer to function that compares keys
//              return 0   if a == b
//              return < 0 if a < b
//              return > 0 if a > b
// returns:
//     handle   use handle in calls to rbt functions


void rbtDelete(RbtHandle h);
// destroy red-black tree

RbtStatus rbtInsert(RbtHandle h, void *key, void *value);
// insert key/value pair

RbtStatus rbtErase(RbtHandle h, RbtIterator i);
// delete node in tree associated with iterator
// this function does not free the key/value pointers

RbtIterator rbtNext(RbtHandle h, RbtIterator i);
// return ++i

RbtIterator rbtBegin(RbtHandle h);
// return pointer to first node

RbtIterator rbtEnd(RbtHandle h);
// return pointer to one past last node

void rbtKeyValue(RbtHandle h, RbtIterator i, void **key, void **value);
// returns key/value pair associated with iterator

RbtIterator rbtFind(RbtHandle h, void *key);
// returns iterator associated with key

#endif

 

红黑树平衡化旋转

红黑树的旋转操作没有AVL树那么复杂,这里的旋转也不区分结点的颜色,纯粹是旋转移动结点的位置,即只有两种操作——左旋和右旋。

1.左旋

红黑树的介绍和实现[原创] - saturnman - 一路

 

static void rotateLeft(RbtType *rbt, NodeType *x) {

    // rotate node x to left

    NodeType *y = x->right;

    // establish x->right link
    x->right = y->left;
    if (y->left != SENTINEL) y->left->parent = x;

    // establish y->parent link
    if (y != SENTINEL) y->parent = x->parent;
    if (x->parent) {
        if (x == x->parent->left)
            x->parent->left = y;
        else
            x->parent->right = y;
    } else {
        rbt->root = y;
    }

    // link x and y
    y->left = x;
    if (x != SENTINEL) x->parent = y;
}
 

 

2.右旋

  红黑树的介绍和实现[原创] - saturnman - 一路

 

static void rotateRight(RbtType *rbt, NodeType *x) {

    // rotate node x to right

    NodeType *y = x->left;

    // establish x->left link
    x->left = y->right;
    if (y->right != SENTINEL) y->right->parent = x;

    // establish y->parent link
    if (y != SENTINEL) y->parent = x->parent;
    if (x->parent) {
        if (x == x->parent->right)
            x->parent->right = y;
        else
            x->parent->left = y;
    } else {
        rbt->root = y;
    }

    // link x and y
    y->right = x;
    if (x != SENTINEL) x->parent = y;
}

 

 红黑树的插入和删除

 

1. 插入操作

    我们总是插入红色的节点,因为这样就可以在插入过程中尽量避免产生对树的调整,我们新插入一个节点后可能使原树的哪些性质改变呢。由于我们是按二叉树的方式插入,因此原树的搜索性质不会改变。如果插入的节点是根节点,性质2会被破坏,如果插入的节点的父节点是红色,则会破坏性质4,因此总的来说,插入一个红色节点只会破坏到性质2或是性质4,我们的恢复树性质的策略很简单,其一就是保持一定的性质不变,之后把出现违背红黑树性质地方向上移,如果能移到根节点,那么很容易就可以通过直接修改根节点来恢复红黑树应满足的性质。其二就是穷举所有的可能性,之后把能归于同一类方法处理的归为同一类,不能直接处理的化归到其它可以直接处理的情况,能直接处理的就直接处理。

下面看看一共有几种情况,

情况1:插入的是根节点(原树是空树)

此情况只会违反性质2

解法:直接把此节点涂为黑色

情况2:插入的节点的的父节点是黑色

此时不会违反性质2也不会违反性质4,红黑树没有被破坏。

解法:什么都不做

情况3:当前节点的父节点是红色且祖父节点的另一个子节点(叔叔节点)是红色(此时父节点的父节点一定存在,否则插入前就已不是红黑树,此时又分为父节点是祖父节点的左子或者右子,对于对称性,只要解开一个方向就可以了,我们只考虑父节点为祖父左子的情况)。此时还可分为当前节点是其父节点的左子还是右子,但是这两种情况的处理方式是一样的,我们将其归为同一类。

解法:将当前节点的父节点和叔叔节点涂黑,祖父结点涂红,把当前结点指向祖父节点,从新的当前节点重新开始算法。

下面是算法导论一书中的图,稍做修改(N代表当前节点,P代表父节点,G代表祖父节点,U代表叔叔节点,以下各图如果相同字母则代表同一意思,不再详述)

变换前

红黑树的介绍和实现[原创] - saturnman - 一路

变换后

红黑树的介绍和实现[原创] - saturnman - 一路

情况4:当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的右子

解法:当前节点的父节点做为新的当前节点,以新当前节点为支点左旋。

如下图所示

变换前

 

红黑树的介绍和实现[原创] - saturnman - 一路

 

变换后

红黑树的介绍和实现[原创] - saturnman - 一路

情况5:当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的左子

解法:父节点变为黑色,祖父节点变为红色,在祖父节点为支点右旋

如下图所示

变换前

红黑树的介绍和实现[原创] - saturnman - 一路

变换后

红黑树的介绍和实现[原创] - saturnman - 一路

在上面的插入算法中,所有递归都是尾递归,可以改写为循环,其中以当前节点的父节点是否为红色是十分方便的。

2.删除操作

    我们删除的节点的方法与常规二叉搜索树中删除节点的方法是一样的,如果被删除的节点不是有双非空子女,则直接删除这个节点,用它的唯一子节点顶替它的位置,如果它的子节点分是空节点,那就用空节点顶替它的位置,如果它的双子全为非空,我们就把它的直接后继节点内容复制到它的位置,之后以同样的方式删除它的后继节点,它的后继节点不可能是双子非空,因此此传递过程最多只进行一次。在册除节点后,原红黑树的性质可能被改变,如果删除的是红色节点,那么原红黑树的性质依旧保持,此时不用做修正操作,如果删除的节点是黑色节点,原红黑树的性质可能会被改变,我们要对其做修正操作。那么哪些树的性质会发生变化呢,如果删除节点不是树唯一节点,那么删除节点的那一个支的到各叶节点的黑色节点数会发生变化,此时性质5被破坏。如果被删节点的唯物主唯一非空子节点是红色,而被删节点的父节点也是红色,那么性质4被破坏。如果被删节点是根节点,而它的唯一非空子节点是红色,则删除后新根节点将变成红色,违背性质2。现在情况看起来有些复杂,这里面我们用一个分析技巧,这引技巧是从《算法导论》一书中学来的。我们从被删节点后来顶替它的那个节点开始调整,并认为它有额外的一重黑色。这里额外一重黑色是什么意思呢,我们不是把红黑树的节点加上除红与黑的另一种颜色,这里只是一种假设,我们认为我们当前指向它,因此空有额外一种黑色,可以认为它的黑色是从它的父节点被删除后继承给它的,它现在可以容纳两种颜色,如果它原来是红色,那么现在是红+黑,如果原来是黑色,那么它现在的颜色是黑+黑。有了这重额外的黑色,原红黑树性质5就能保持不变。现在只要花时是恢复其它性质就可以了,做法还是尽量向根移动和穷举所有可能性。

情况1:当前节点是红+黑色

    解法,直接把当前节点染成黑色,结束。

此时红黑树性质全部恢复。

情况2:当前节点是黑+黑且是根节点

    解法:什么都不做,结束

情况3:当前节点是黑+黑且兄弟节点为红色(此时父节点和兄弟节点的子节点分为黑)

    解法:把父节点染成红色,把兄弟结点染成黑色,之后重新进入算法(我们只讨论当前节点是其父节点左孩子时的情况)。此变换后原红黑树性质5不变,而把问题转化为兄弟节点为黑色的情况。

变换前

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

 

 

变换后

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

 情况4:当前节点是黑加黑且兄弟是黑色且兄弟节点的两个子节点全为黑色

    解法:把当前节点和兄弟节点中抽取一重黑色追加到父节点上,把父节点当成新的当前节点,重新进入算法。(此变换后性质5不变)

变换前

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

 

 

变换后

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

情况5:当前节点颜色是黑+黑,兄弟节点是黑色,兄弟的左子是红色,右子是黑色。

 

解法:把兄弟结点染红,兄弟左子节点染黑,之后再在兄弟节点为支点解右旋,之后重新进入算法。此是把当前的情况转化为情况6,而性质5得以保持。

变换前

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

 变换后

 

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

 情况6:当前节点颜色是黑-黑,它的兄弟节点是黑色,但是兄弟节点的右子是红色,兄弟节点左子的颜色任意。

 

解法:把兄弟节点染成当前节点父节点的颜色,把当前节点父节点染成黑色,兄弟节点右子染成黑色,之后以当前节点的父节点为支点进行左旋,此时算法结束,红黑树所有性质调整正确。

 

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

 变换后

 

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

 

红黑树的高度分析

包含n个内部节点的红黑树的高度是 O(log(n))。

定义:

  • h(v) = 以节点v为根的子树的高度。
  • bh(v) = 从v到子树中任何叶子的黑色节点的数目(如果v是黑色则不计数它)(也叫做黑色高度)。

引理: 以节点v为根的子树有至少2^{bh(v)}-1个内部节点。

引理的证明(通过归纳高度):

基础: h(v) = 0

如果v的高度是零则它必定是 nil,因此 bh(v) = 0。所以:


2^{bh(v)}-1 = 2^{0}-1 = 1-1 = 0

归纳假设: h(v) = k 的v有 2^{bh(v)-1}-1 个内部节点暗示了 h(v') = k+1 的 v'2^{bh(v')}-1 个内部节点。

因为 v' 有 h(v') > 0 所以它是个内部节点。同样的它有黑色高度要么是 bh(v') 要么是 bh(v')-1 (依据v'是红色还是黑色)的两个儿子。通过归纳假设每个儿子都有至少 2^{bh(v')-1}-1 个内部接点,所以 v' 有:


2^{bh(v')-1}-1 + 2^{bh(v')-1}-1 + 1 = 2^{bh(v')}-1

个内部节点。

使用这个引理我们现在可以展示出树的高度是对数性的。因为在从根到叶子的任何路径上至少有一半的节点是黑色(根据红黑树属性4),根的黑色高度至少是h(root)/2。通过引理我们得到:


n \geq 2^{{h(root) \over 2}} - 1 \leftrightarrow \; \log{(n+1)} \geq {h(root) \over 2} \leftrightarrow \; h(root) \leq 2\log{(n+1)}

因此根的高度是O(log(n))。

 

下面附上完整的实现代码

 

 

// red-black tree

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

//////////////////////
// supplied by user //
//////////////////////

typedef int KeyType;            // type of key

typedef struct {                // value related to key
    int stuff;
} ValType;

// how to compare keys
#define compLT(a,b) (a < b)
#define compEQ(a,b) (a == b)

/////////////////////////////////////
// implementation independent code //
/////////////////////////////////////

typedef enum {
    RBT_STATUS_OK,
    RBT_STATUS_MEM_EXHAUSTED,
    RBT_STATUS_DUPLICATE_KEY,
    RBT_STATUS_KEY_NOT_FOUND
} RbtStatus;

typedef enum { BLACK, RED } nodeColor;

typedef struct NodeTag {
    struct NodeTag *left;       // left child
    struct NodeTag *right;      // right child
    struct NodeTag *parent;     // parent
    nodeColor color;            // node color (BLACK, RED)
    KeyType key;                // key used for searching
    ValType val;                // data related to key
} NodeType;

#define SENTINEL &sentinel      // all leafs are sentinels
static NodeType sentinel = { SENTINEL, SENTINEL, 0, BLACK, 0};

static NodeType *root = SENTINEL; // root of red-black tree

static void rotateLeft(NodeType *x) {

    // rotate node x to left

    NodeType *y = x->right;

    // establish x->right link
    x->right = y->left;
    if (y->left != SENTINEL) y->left->parent = x;

    // establish y->parent link
    if (y != SENTINEL) y->parent = x->parent;
    if (x->parent) {
        if (x == x->parent->left)
            x->parent->left = y;
        else
            x->parent->right = y;
    } else {
        root = y;
    }

    // link x and y
    y->left = x;
    if (x != SENTINEL) x->parent = y;
}

static void rotateRight(NodeType *x) {

    // rotate node x to right

    NodeType *y = x->left;

    // establish x->left link
    x->left = y->right;
    if (y->right != SENTINEL) y->right->parent = x;

    // establish y->parent link
    if (y != SENTINEL) y->parent = x->parent;
    if (x->parent) {
        if (x == x->parent->right)
            x->parent->right = y;
        else
            x->parent->left = y;
    } else {
        root = y;
    }

    // link x and y
    y->right = x;
    if (x != SENTINEL) x->parent = y;
}

static void insertFixup(NodeType *x) {

    // maintain red-black tree balance
    // after inserting node x

    // check red-black properties
    while (x != root && x->parent->color == RED) {
        // we have a violation
        if (x->parent == x->parent->parent->left) {
            NodeType *y = x->parent->parent->right;
            if (y->color == RED) {

                // uncle is RED
                x->parent->color = BLACK;
                y->color = BLACK;
                x->parent->parent->color = RED;
                x = x->parent->parent;
            } else {

                // uncle is BLACK
                if (x == x->parent->right) {
                    // make x a left child
                    x = x->parent;
                    rotateLeft(x);
                }

                // recolor and rotate
                x->parent->color = BLACK;
                x->parent->parent->color = RED;
                rotateRight(x->parent->parent);
            }
        } else {

            // mirror image of above code
            NodeType *y = x->parent->parent->left;
            if (y->color == RED) {

                // uncle is RED
                x->parent->color = BLACK;
                y->color = BLACK;
                x->parent->parent->color = RED;
                x = x->parent->parent;
            } else {

                // uncle is BLACK
                if (x == x->parent->left) {
                    x = x->parent;
                    rotateRight(x);
                }
                x->parent->color = BLACK;
                x->parent->parent->color = RED;
                rotateLeft(x->parent->parent);
            }
        }
    }
    root->color = BLACK;
}

// insert new node (no duplicates allowed)
RbtStatus rbtInsert(KeyType key, ValType val) {
    NodeType *current, *parent, *x;

    // allocate node for data and insert in tree

    // find future parent
    current = root;
    parent = 0;
    while (current != SENTINEL) {
        if (compEQ(key, current->key)) 
            return RBT_STATUS_DUPLICATE_KEY;
        parent = current;
        current = compLT(key, current->key) ?
            current->left : current->right;
    }

    // setup new node
    if ((x = malloc (sizeof(*x))) == 0)
        return RBT_STATUS_MEM_EXHAUSTED;
    x->parent = parent;
    x->left = SENTINEL;
    x->right = SENTINEL;
    x->color = RED;
    x->key = key;
    x->val = val;

    // insert node in tree
    if(parent) {
        if(compLT(key, parent->key))
            parent->left = x;
        else
            parent->right = x;
    } else {
        root = x;
    }

    insertFixup(x);

    return RBT_STATUS_OK;
}

static void deleteFixup(NodeType *x) {

    // maintain red-black tree balance
    // after deleting node x

    while (x != root && x->color == BLACK) {
        if (x == x->parent->left) {
            NodeType *w = x->parent->right;
            if (w->color == RED) {
                w->color = BLACK;
                x->parent->color = RED;
                rotateLeft (x->parent);
                w = x->parent->right;
            }
            if (w->left->color == BLACK && w->right->color == BLACK) {
                w->color = RED;
                x = x->parent;
            } else {
                if (w->right->color == BLACK) {
                    w->left->color = BLACK;
                    w->color = RED;
                    rotateRight (w);
                    w = x->parent->right;
                }
                w->color = x->parent->color;
                x->parent->color = BLACK;
                w->right->color = BLACK;
                rotateLeft (x->parent);
                x = root;
            }
        } else {
            NodeType *w = x->parent->left;
            if (w->color == RED) {
                w->color = BLACK;
                x->parent->color = RED;
                rotateRight (x->parent);
                w = x->parent->left;
            }
            if (w->right->color == BLACK && w->left->color == BLACK) {
                w->color = RED;
                x = x->parent;
            } else {
                if (w->left->color == BLACK) {
                    w->right->color = BLACK;
                    w->color = RED;
                    rotateLeft (w);
                    w = x->parent->left;
                }
                w->color = x->parent->color;
                x->parent->color = BLACK;
                w->left->color = BLACK;
                rotateRight (x->parent);
                x = root;
            }
        }
    }
    x->color = BLACK;
}

// delete node
RbtStatus rbtErase(NodeType * z) {
    NodeType *x, *y;

    if (z->left == SENTINEL || z->right == SENTINEL) {
        // y has a SENTINEL node as a child
        y = z;
    } else {
        // find tree successor with a SENTINEL node as a child
        y = z->right;
        while (y->left != SENTINEL) y = y->left;
    }

    // x is y's only child
    if (y->left != SENTINEL)
        x = y->left;
    else
        x = y->right;

    // remove y from the parent chain
    x->parent = y->parent;
    if (y->parent)
        if (y == y->parent->left)
            y->parent->left = x;
        else
            y->parent->right = x;
    else
        root = x;

    if (y != z) {
        z->key = y->key;
        z->val = y->val;
    }


    if (y->color == BLACK)
        deleteFixup (x);

    free (y);

    return RBT_STATUS_OK;
}

// find key
NodeType *rbtFind(KeyType key) {
    NodeType *current;
    current = root;
    while(current != SENTINEL) {
        if(compEQ(key, current->key)) {
            return current;
        } else {
            current = compLT (key, current->key) ?
                current->left : current->right;
        }
    }
    return NULL;
}

// in-order walk of tree
void rbtInorder(NodeType *p, void (callback)(NodeType *)) {
    if (p == SENTINEL) return;
    rbtInorder(p->left, callback);
    callback(p);
    rbtInorder(p->right, callback);
}

// delete nodes depth-first
void rbtDelete(NodeType *p) {
    if (p == SENTINEL) return;
    rbtDelete(p->left);
    rbtDelete(p->right);
    free(p);
}

void displayNode(NodeType *p) {
    printf("%d %d\n", p->key, p->val.stuff);
}

int main(int argc, char **argv) {
    int maxnum, ct;
    KeyType key;
    RbtStatus status;

    // command-line:
    //
    //   rbt 2000
    //      process 2000 records

    NodeType *p;

    maxnum = atoi(argv[1]);

    printf("maxnum = %d\n", maxnum);
    for (ct = maxnum; ct; ct--) {
        key = rand() % 90 + 1;
        if ((p = rbtFind(key)) != NULL) {
            if (p->val.stuff != 10*key) printf("fail val\n");
            status = rbtErase(p);
            if (status) printf("fail: status = %d\n", status);
        } else {
            ValType val;
            val.stuff = 10*key;
            status = rbtInsert(key, val);
            if (status) printf("fail: status = %d\n", status);
        }
    }

    // output nodes in order
    rbtInorder(root, displayNode);

    rbtDelete(root);

    return 0;
}
 

 

 

 

参考:

Implementation in C: http://epaperpress.com/sortsearch/txt/rbt.txt 

②维基百科: http://zh.wikipedia.org/zh/%E7%BA%A2%E9%BB%91%E6%A0%91

http://epaperpress.com/sortsearch/rbt.html

saturnma http://saturnman.blog.163.com/blog/static/5576112010969420383/

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    关于红黑树(Red-Black Tree)英文论文

    关于红黑树(Red-Black Tree)英文论文,全英文写作,分析全面,到位,结合当前新技术进展总结而成。

    C#,红黑树(Red-Black Tree)的构造,插入、删除及修复、查找的算法与源代码

    C#,红黑树(Red-Black Tree)的构造,插入、删除及修复、查找的算法与源代码 1 红黑树(Red-Black Tree) 如果二叉搜索树满足以下红黑属性,则它是红黑树: 每个节点不是红色就是黑色。 根是黑色的。 每片叶子(无...

    红黑树(Red-Black Tree)代码

    红黑树(Red-Black Tree)是二叉搜索树(Binary Search Tree)的一种改进。我们知道二叉搜索树在最坏的情况下可能会变成一个链表(当所有节点按从小到大的顺序依次插入后)。而红黑树在每一次插入或删除节点 之后...

    红黑树 RBTREE red-black-tree RBTree RED BLACK TREE

    这一版代码个人认为99.99%正确,本人使用些结构及算法用于实现嵌入式迅雷Server的任务管理。此代码经本人学习研究之后从C语言版BT源代码中的宏定义式代码中分离出来,并做成一...希望对需要学习红黑树的人有帮助。

    Linux内核红黑树封装的通用红黑树

    Red-black tree the Linux kernel package with a omnipotent red-black tree how to use: see rbtest1.c and rbtest2.c Directly generate rbtest1 and rbtest2 make You can modify and run author: rcyh ...

    RED-BLACK-tree-and-2-3-4tree.rar_234树到红黑树_红黑树

    红黑树的发明者关于红黑树的演化过程的介绍,是最好的理解红黑树的资料。

    red-black-tree(delete)

    red-black-tree(delete).,关于红黑树删除方法的仔细讲解

    redblack tree 红黑树代码

    红黑树C语言代码: #include "redblack.h" #include #include "fatal.h" 头文件: #include #include "fatal.h" typedef int ElementType; #define NegInfinity (-10000) #ifndef _RedBlack_H #define _Red...

    red-black-tree:Ada 2012实施一棵红黑树

    红黑树 这是Ada 2012对(一种自平衡二进制搜索树)的实现。 该树使用标准的Ada.Iterator_Interfaces进行迭代。 with Ada.Integer_Text_IO ; use Ada.Integer_Text_IO; with Ada.Text_IO ; use Ada.Text_IO; with ...

    Red-Black Tree

    红黑树,详细的代码过程,完整的代码实现,希望对大家有帮助,第一次上传,为了赚积分,

    red-black-tree-c.rar_red black tree_tree c语言

    红黑树的源代码,c语言版本。非常的详细。

    Algorithm-redblack-tree

    红黑树 java代码

    红黑树(Red Black Tree)

    红黑树的详细描述,从数据结构到创建,最小值,最大值,后继,遍历,插入以及删除。 该代码是clion IDE中实现的,代码全部在main.c中。

    RedBlackTree.rar

    此工程主要包含红黑树的插入和删除,采用C++编写,有单独的.h和.cpp文件,方便移植

    RedBlackTree.zip

    红黑树(Red Black Tree)是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。 红黑树是一种特化的AVL树(平衡二叉树),都是在进行插入和删除操作时通过特定操作保持二叉树的...

    red-black-tree.zip

    红黑树的C语言实现

    js-red-black-tree:JavaScript的红黑树库

    :Christmas_tree: let tree = RedBlackTree . from ( increasing , range ( 100000 ) ) ; JavaScript的红黑树库。 请参阅。 父母是 。

    Red-Black-Tree.tar.gz

    红黑树C语言代码,qt工程,红黑树在linux C++:STL中应用广泛,而且很多面试时喜欢问。

    redblack tree

    因为实验要求指定了输入哪些数据,所以在实现时我用了一个数组将所有的数据保存到内存里,然后直接调用插入和删除操作,这样就不再需要用户输入数据,省去了输入...插入8,11,17,15,6,1,22,25,27后,遍历红黑树

    Red-Black-Tree:GENERIC 数据类型的红黑(平衡)二叉搜索树的实现

    版权所有##Description 这个作业需要实现我自己的红黑(平衡)二叉搜索树来存储 GENERIC 数据类型。 此外,“Word”类是要在树中存储/搜索的数据类型。 TimingTests 类应从文本文件中读取,并将文件中的所有单词...

Global site tag (gtag.js) - Google Analytics