C++ Learning——Build a simple&little RB_Tree

Why would we go to such ludicrous lebgths to explain the RB_TREE?

《STL源码剖析》上给了我们一个很好的解释:(见202页)

所谓树形平衡与否,并没有一个绝对的测量标准。“平衡”的大致意义是:没有一个节点过深(深度即就是“根节点至任一节点的路径长度,即所谓该节点的深度”,在数值上与路径长度相等)。不同的平衡条件,造就出不同的效率表现,以及不同的实现复杂度。有数种特殊结构如:AVL-Tree,RB-tree,AA-tree,均可实现出平衡二叉搜索树,他们都比一般的(无法绝对维持平衡的)二叉搜索树更加复杂,因此,插入节点和删除节点的平均时间也比较长,但是他们可以避免极难应付的(高度不平衡)最坏情况,而且由于他们总是保持某种程度的平衡,所以元素的访问(搜寻)时间平均而言也就比较少,一般而言其搜寻时间可以节省25%左右

一个平衡二叉搜索树之RB_Tree.它不仅是一个二叉搜索树,还应该满足以下规则:

概括起来即是“一头一脚黑,黑同红不连”:

我们约定四个规则:

(1)每个节点不是红色就是黑色

(2)根节点必须为黑色(即一头一脚黑,其中一脚指的是空节点)

(3)如果节点为红,其子节点必须为黑(即红不连)

(4)任一节点到NULL(树尾端)的任何路径,所含之黑节点数必须相同。 (即黑同)

Here are the RB_TREE code && explanation:(You also can actualize it.Believe yourself!)

/*头文件*/
#include<iostream>
#include<assert.h>   //for assert
#include<string.h>   //for memset

/*memset用法:
* void *memset(void *s, int c, size_t n);
*  The  memset() function fills the first n bytes of the memory area
* pointed to by s with the constant byte c.
*/

using namespace std;

/*树节点颜色用枚举类型来定义
*typedef的使用方法见我的另一篇文章[typedef用法汇总](http://blog.csdn.net/derkampf/article/details/51339953)
*这里用来定义节点中所存实值的类型。
*/
typedef int Type;
typdef enum{RED=0, BLACK}Color;

typedef struct Node
{
    Color color;
    Type key;
    struct Node *left, *right, *parent;
}*PNode;    //节点的类型为指针类型

typedef struct
{
    Node *root;
    Node *Nil;
}RB_TREE;    //RB_TREE节点内容,Nil为一个工具,为后续树之节点的的赋空、判空起作用

Node* Buynode()
{
    Node *p = new Node;
    assert(p != NULL);
    memset(p,0,sizeof(Node));    //为新增节点节点初始化,{color = RED, key = 0, left = 0x0, right = 0x0, parent = 0x0}
    return p;
}

void InitTree(RB_TREE &t)    //创建节点并对其初始化
{
    t.Nil = Buynode();
    t.root = t.Nil;
    t.Nil->color = BLACK;
    t.Nil->key = -1;
}

/*左旋、右旋,以及插入之后将红黑树平衡的代码置于后面进行分析*/

bool Insert(RB_TREE &t, Type x)    //插入节点
{
    Node *p = t.Nil;
    Node *s = t.root;
    /*从根结点开始遍历,找到属于新增节点q的位置,将其插入*/
    while(s != t.Nil)
    {
    p = s;
    if(x == s->key)
    {
        return false;
        }
        else if(x < s->key)
        {
        s = s->left;    //说明x的位置应该在此时s的左树位置查找
    }
    else
    {
        s = s->right;    //那么此时x应插入的位置应该继续在s的右树上寻找
    }
    }
    /*到达此步,程序已经找到新增节点的位置,接下来要做的是:新建一个空节点q,将x的值给与该结点(这就构成我们要插入的新节点)*/
    Node *q = Buynode();
    q->key = x;
    q->parent = p;   //仔细想想,这里不能写q->parent = s;因为程序执行到这里的时候s = t.Nil,即s为NULL
    /*后续操作*/
    if(p == t.Nil)    //这里我感觉可以没有这个条件,因为此时p是存在的
    {
        t.root = q;
    }
    else if(x < p->key)
    {
        p->left = q;
    }
    else
    {
        p->right = q;
    }
    q->left = q->right = t.Nil;
    q->color = RED;    //新插入节点颜色须为红色
    Insert_Fixup(t,q); //需要进一步修正一下,是的满足RB_TREE的规则
    return true;
}

int main()
{
    int ar[] = {5,7,10};
    RB_TREE rb;
    InitTree(rb);
    for(int i = 0; i<sizeof(ar) / sizeof(int); ++i)
    {
        Insert(rb, ar[i]);
    }
    return 0;
}

插入的节点会破坏RB_Tree的规则,致使我们必须旋转树形并调整节点的颜色。书中给了我们四种考虑办法。

“根据x的插入位置即外围节点(s伯父节点和GG曾祖父节点)的颜色,有了四种考虑”

——《STL源码剖析》

因为是简单实现,我们只来剖析一下单旋转的情况。后面我将陆续为大家更新SGI–STL版红黑树的实现过程,敬请期待!

下面即为左旋、右旋,以及插入之后将红黑树平衡之的代码:

情况如下:

(详情见《STL源码剖析》210页,这里不再赘述)

//有了上面的树,得到下面的代码是显而易见的
void Rotateleft(RB_TREE &t, Node *p)
{
    Node *s = p->right;
    P->right = s->left;
    if(s->left != t.Nil)
    {
    s->left->parent = p;
    }
    s->parent = p->parent;
    if(p->parent = t.Nil)
    {
    t.root = s;
    }
    else if(p = p->parent->left)
    {
    p->parent->left = s;
    }
    else
    {
    p->parent->right = s;
    }
    s->left = p;
    p->parent = s;
}

//上面是右旋的示意图,只要考虑到所会出现的各种情况,那么就可以写出通用的右旋代码。
void Rotateright(RB_TREE &t, Node *p)
{
    Node *s = p->left;
    p->left = s->right;
    if(s->right != t.Nil)
    {
        s->right->parent = p;
    }
    s->parent = p->parent;
    if(p->parent == t>Nil)
    {
    t.root = s;
    }
    else if(p == p->parent->left)
    {
    p->parent->left = s;
    }
    else
    {
    p->parent->right = s;
    }
    s->right = p;
    p->parent = s;
}

我们要知道的是,一段代码用来解决一个问题,如果考虑到各种可能会出现的情况,那么这段代码便可以完美的解决这个问题中出现的所有情况。就像上述的左旋,右旋代码,我们只用它来解决左旋,或者右旋的问题,在编写代码的时候,我们已经考虑到了在这一过程中会出现的情况,那么它不仅仅只局限于简单的树,而是所有需要进行左旋或者右旋的树。

void Insert_Fixup(RB_TREE &t, Node *z)
{
    
}

时间: 2024-12-20 17:43:33

C++ Learning——Build a simple&little RB_Tree的相关文章

Basics of Ensemble Learning Explained in Simple English

Basics of Ensemble Learning Explained in Simple English Introduction Ensemble modeling is a powerful way to improve performance of your model. It usually pays off to apply ensemble learning over and above various models you might be building. Time an

《Let&#39;s Build A Simple Interpreter》之 Golang 版

一直以来对编译器/解释器等都较有兴趣.我非科班出身,当初还在大学时,只是马马虎虎看完了<编译原理>之类教材,上机非常少,对龙书之类圣经也只是浅尝辄止而已.工作至今,基本已将编译原理相关知识忘记得差不多了,可能也就还对譬如预处理词法分析语法分析 AST 生成等基础性的概念还有点印象罢. 约 1 年多前,我也有想法搞一套基于简化的 Pascal 语法的带类型的脚本语言"编译器"(PaxCompiler 之类可能太复杂了),并将此脚本语言编写的脚本与 Golang 交互起来.当然

[Transducer] Step by Step to build a simple transducer

Transducers are composable algorithmic transformations. They are independent from the context of their input and output sources and specify only the essence of the transformation in terms of an individual element. Because transducers are decoupled fr

Udacity Nanodegree Program: Deep Learning Foundation: New Syllusbus

Program Structure Every week, you can expect to see this content coming up: Siraj's introductory video & One hour coding session Additional lesson(s) from Mat & other Udacity experts Then, approximately every four weeks you'll get a project. The f

I finally made sense of front end build tools. You can, too.

来源于:https://medium.freecodecamp.com/making-sense-of-front-end-build-tools-3a1b3a87043b#.nvnd2vsd8 Front end build tools can be confusing even to experienced developers like me. The solution is to understand how they work - and work together - on a co

The Brain as a Universal Learning Machine

The Brain as a Universal Learning Machine This article presents an emerging architectural hypothesis of the brain as a biological implementation of a Universal Learning Machine.  I present a rough but complete architectural view of how the brain work

【转】The most comprehensive Data Science learning plan for 2017

I joined Analytics Vidhya as an intern last summer. I had no clue what was in store for me. I had been following the blog for some time and liked the community, but did not know what to expect as an intern. The initial few days were good – all the in

Machine Learning for Developers

Machine Learning for Developers Most developers these days have heard of machine learning, but when trying to find an 'easy' way into this technique, most people find themselves getting scared off by the abstractness of the concept of Machine Learnin

[PReact] Handle Simple Routing with preact-router

Some applications only need a very minimal routing solution. This lesson will cover a practical example showing the router in use. We’ll build a simple search feature that accepts user input and then calls the github API. We’ll see how to access rout