说说红黑树

原创
2017/02/06 21:00
阅读数 144

红黑树的性质:
        红黑树的每个节点(node)都有一个flag位,不是红色(Red)就是黑色(Black)。通过对任意一条从跟节点到叶子节点的简单路径的颜色加以约束,可以保证没有
一条路径会比其它路径长出2倍,这样便使得红黑树可以达到近似平衡的。
        每个node包含5个属性和所属数据,当然有些优化了的红黑树可能更为复杂,这里不讨论。
            typedef struct Node{
                struct Node* left;  //指向左子节点
                struct Node* right; //指向右子节点
                enum Color color;   //节点颜色
                int key;            //关键字
                struct Node* p;     //节点的父节点
                struct Data* data;  //节点数据,前5个为属性
            } *rb_node_ptr,rb_node;
        一颗红黑树必定满足以下5个性质:
            1.每个节点是黑色或红色;
            2.跟节点是黑色;
            3.红色节点的子节点必定为黑色;
            4.叶子节点为黑色;
            5.从一个节点出发(不包含该节点)到叶子节点的任意简单路径所经过的黑色节点数目必定一致。
        通常使用哨兵来处理红黑树的边界条件。所谓红黑树的哨兵,就是增加一个节点来收集所有指向叶子节点的普通节点的指向,这样不会影响红黑树的性质,而且可以节省空间。由于节点到叶子节点的任意简单路径所经过的黑节点数目是明确定义的,因此定义为从跟节点到叶子节点的所经过的黑节点数目,称为“黑高(black-height)。

 

红黑树数型改变时性质的维护:
        随着红黑树的树形变化,比如在add,delete等操作后,会改变当前树形。为维持红黑树的性质必需对数据节点进行调整。

节点的旋转:
        维持红黑树的性质的方法是对节点进行旋转,旋转包括左旋和右旋。旋转操作并不会改变关键字的前后顺序。个人理解这个左旋和右旋其实理解为顺时针旋转和逆时针旋转更形象。旋转涉及到两个节点x,y和三个子树alpha,gama,beta,如图所示。

添加数据:

C++代码清单:

redblacktree.h

#ifndef _REDBLACKTREE_NODE_
#define _REDBLACKTREE_NODE_
#include<iostream>
enum Color
{
    RED,
    BLACK
};

struct data
{
  int d;
};
typedef struct RedBlackTreeNode
{
    struct data use_data;
    int key;
    struct RedBlackTreeNode* lchild;
    struct RedBlackTreeNode* rchild;
    struct RedBlackTreeNode* parent;
    enum Color color;
}red_black_tree_node,*red_black_tree_node_ptr;

class RedBlackTree
{
private:
    red_black_tree_node_ptr root;
    red_black_tree_node     guard;
public:
    RedBlackTree();
    ~RedBlackTree();
private:
    void init_tree();
    void destroy_tree();
    void red_black_tree_fixup(red_black_tree_node_ptr);
public:
    void insert_node(red_black_tree_node&);
private:
    red_black_tree_node_ptr get_node_ptr(red_black_tree_node&);
    void left_rotate(red_black_tree_node_ptr&);
    void right_rotate(red_black_tree_node_ptr&);
};
#endif //redblacktree.h

redblacktree.cc 

#include "redblacktree.h"
#include <cstdio>
#include <iostream>

RedBlackTree::RedBlackTree()
{
  init_tree();
}

RedBlackTree::~RedBlackTree()
{
    destroy_tree();
}

void RedBlackTree::init_tree()
{
    this->guard.color = BLACK;
    this->guard.lchild = NULL;
    this->guard.rchild = NULL;
    this->guard.parent = NULL;
    this->guard.key = 0;
    this->root = get_node_ptr(this->guard);
}

void RedBlackTree::destroy_tree()
{

}

red_black_tree_node_ptr RedBlackTree::get_node_ptr(red_black_tree_node& node)
{
    return &node;
}

void RedBlackTree::insert_node(red_black_tree_node& node)
{
    red_black_tree_node_ptr y_ptr = get_node_ptr(this->guard);
    red_black_tree_node_ptr x_ptr = this->root;
    while(x_ptr != get_node_ptr(this->guard)){
	y_ptr = x_ptr;
	if(node.key <= x_ptr->key)
	    x_ptr = x_ptr->lchild;
	else 
	    x_ptr = x_ptr->rchild;
    }
    node.parent = y_ptr;
    
    if(y_ptr == get_node_ptr(this->guard)){
	this->root = get_node_ptr(node);
    }
    else if(node.key <= y_ptr->key){
	y_ptr->lchild = get_node_ptr(node);	
    }
    else{
	y_ptr->rchild = get_node_ptr(node);
    }
node.lchild = get_node_ptr(this->guard);
node.rchild = get_node_ptr(this->guard);
node.color = RED;

red_black_tree_fixup(get_node_ptr(node));
}

void RedBlackTree::red_black_tree_fixup(red_black_tree_node_ptr node_ptr)
{
    while(node_ptr->parent->color == RED){
	if(node_ptr->parent == node_ptr->parent->parent->lchild){
	    red_black_tree_node_ptr uncle_ptr = node_ptr->parent->parent->rchild;
	    if(uncle_ptr->color == RED){
		node_ptr->parent->color = BLACK;
		uncle_ptr->color = BLACK;
		node_ptr->parent->parent->color = RED;
		
		node_ptr = node_ptr->parent->parent;
	    }
	    else if(node_ptr == node_ptr->parent->rchild){
		node_ptr = node_ptr->parent;
		left_rotate(node_ptr);
	    }
	    node_ptr->parent->color = BLACK;
	    node_ptr->parent->parent->color = RED;
	    right_rotate(node_ptr->parent->parent);
	}
	else if(node_ptr->parent == node_ptr->parent->parent->rchild){
	    red_black_tree_node_ptr uncle_ptr = node_ptr->parent->parent->lchild;
	    if(uncle_ptr->color == RED){
		node_ptr->parent->color = BLACK;
		uncle_ptr->color = BLACK;
		node_ptr->parent->parent->color = RED;
		node_ptr = node_ptr->parent->parent;
	    }
	    else if(node_ptr == node_ptr->parent->lchild){
		node_ptr = node_ptr->parent;
		right_rotate(node_ptr);
	    }
	    node_ptr->parent->color = BLACK;
	    node_ptr->parent->parent->color = RED;
	    left_rotate(node_ptr->parent->parent);
	}
    }

this->root->color = BLACK;
}

void RedBlackTree::left_rotate(red_black_tree_node_ptr& node_ptr)
{
    red_black_tree_node_ptr right_sub_node_ptr = node_ptr->rchild;
    node_ptr->rchild = right_sub_node_ptr->lchild;
    if(right_sub_node_ptr->lchild != get_node_ptr(this->guard)){
	right_sub_node_ptr->lchild->parent = node_ptr;
    }
    right_sub_node_ptr->parent = node_ptr->parent;

    if(node_ptr->parent == get_node_ptr(this->guard)){
	this->root = right_sub_node_ptr;
    }
    else if(node_ptr == node_ptr->parent->lchild){
	node_ptr->parent->lchild = right_sub_node_ptr;
    }
    else{
	node_ptr->parent->rchild = right_sub_node_ptr;
    }
    
    right_sub_node_ptr->lchild = node_ptr;
    node_ptr->parent = right_sub_node_ptr;
}

void RedBlackTree::right_rotate(red_black_tree_node_ptr& node_ptr)
{
    red_black_tree_node_ptr left_sub_node_ptr = node_ptr->lchild;
    node_ptr->lchild = left_sub_node_ptr->rchild;
    if(left_sub_node_ptr->rchild != get_node_ptr(this->guard)){
	left_sub_node_ptr->rchild->parent = node_ptr;
    }
    left_sub_node_ptr->parent = node_ptr->parent;
    
    if(node_ptr->parent == get_node_ptr(this->guard)){
	this->root = left_sub_node_ptr;
    }
    else if(node_ptr == node_ptr->parent->rchild){
	node_ptr->parent->rchild = left_sub_node_ptr;
    }
    else{
	node_ptr->parent->lchild = left_sub_node_ptr;
    }

    left_sub_node_ptr->rchild = node_ptr;
    node_ptr->parent = left_sub_node_ptr;
}

main.cc

#include "redblacktree.h"

int main()
{
  RedBlackTree tree;
  red_black_tree_node node1;
  node1.key = 11;
  tree.insert_node(node1);  
  red_black_tree_node node2;
  node2.key = 12;
  tree.insert_node(node2);  
return 0;
}

 

搞清楚节点和节点指针的关系:

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部