1. 程式人生 > >將部落格搬至CSDN —— 說說紅黑樹

將部落格搬至CSDN —— 說說紅黑樹

兩年前在oschina寫的,現在搬到CSDN來,原部落格地址:https://my.oschina.net/u/2309100/blog/832916

紅黑樹的性質:
        紅黑樹的每個節點(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;
}

搞清楚節點和節點指標的關係: