算法導論 紅黑樹 學習 插入(三)

學習算法 還是建議看看算法導論

算法導論第三版 如果不看數學推導 僅看僞代碼 難度還是適中

本系列只是記錄我的學習心得 和僞代碼轉化代碼的過程

深入學習 還是建議大家看看算法書籍 教程更加系統。

本文參考算法導論第13章節 紅黑樹

代碼由本人寫成

轉載請標明出處

 

現在說插入元素

紅黑樹的插入跟二叉樹的插入差不多 首先是查找合適的位置

插入 insert

注意 插入節點的顏色肯定是紅色的

插入後由於有顏色的限制 要進行調整 insertfix

僞代碼見 算法導論


代碼和插入步驟圖如下:

void RBInsert(std::shared_ptr<node>& root, std::shared_ptr<node> ins) {
    std::shared_ptr<node> y = nil;
    std::shared_ptr<node> x = root;
 
    while (x != nil) {
        y = x;
        if (ins->value_ < x->value_) {
            x = x->left_;
        }
        else {
            x = x->right_;
        }
    }
    ins->parent_ = y;
    if (y == nil) {
        root = ins;
    }
    else if (ins->value_ < y->value_) {
        y->left_ = ins;
    }
    else {
        y->right_ = ins;
    }
    ins->left_ = ins->right_ = nil;
    ins->color_ = red;
    // todo  fixup
 
    //RBInsertFixup(root, ins);
}
先不管插入後的顏色調整 來看看插入的步驟是怎麼樣的

#include <memory>
#include <iostream>
 
using namespace std;
 
enum Color {
    red = 1,
    black
};
 
struct node {
    Color color_;
    std::shared_ptr<node> left_;
    std::shared_ptr<node> right_;
    std::shared_ptr<node> parent_;
    int value_;
    node() {
        left_ = right_ = parent_ = nullptr;
        value_ = -1;
        color_ = black;
    }
};
 
std::shared_ptr<node> nil(new node);
 
 
std::shared_ptr<node> CreateNode(Color color, int i) {
    std::shared_ptr<node> p(new node);
    p->color_ = color;
    p->left_ = nil;
    p->right_ = nil;
    p->parent_ = nil;
    p->value_ = i;
    return p;
}
 
void PrinTree(std::shared_ptr<node> root);
 
 
void RBInsert(std::shared_ptr<node>& root, std::shared_ptr<node> ins) {
    std::shared_ptr<node> y = nil;
    std::shared_ptr<node> x = root;
 
    while (x != nil) {
        y = x;
        if (ins->value_ < x->value_) {
            x = x->left_;
        }
        else {
            x = x->right_;
        }
    }
    ins->parent_ = y;
    if (y == nil) {
        root = ins;
    }
    else if (ins->value_ < y->value_) {
        y->left_ = ins;
    }
    else {
        y->right_ = ins;
    }
    ins->left_ = ins->right_ = nil;
    ins->color_ = red;
    // todo  fixup
 
    //RBInsertFixup(root, ins);
}
 
void PrinTree(std::shared_ptr<node> root) {
    if (root == nil) {
        return;
    }
    std::cout << root->value_ << " ";
    if (root->left_ != nil)
        PrinTree(root->left_);
    if (root->right_ != nil)
        PrinTree(root->right_);
}
 
int main()
{
    std::shared_ptr<node> root = CreateNode(black, 15);
    root->parent_ = nil;
 
    std::shared_ptr<node> x = root;
    std::shared_ptr<node> ins = CreateNode(black, 10);
    RBInsert(x, ins);
     
    ins = CreateNode(black, 20);
    RBInsert(x, ins);
 
    ins = CreateNode(black, 25);
    RBInsert(x, ins);
 
    ins = CreateNode(black, 12);
    RBInsert(x, ins);
 
    ins = CreateNode(black, 17);
    RBInsert(x, ins);
 
 
    PrinTree(root);
    std::cout << std::endl;
 
 
    return 0;
}

  我們依次插入15 10 20 25 12 17


但是插入節點的時候,各個節點的顏色可能會破壞部分紅黑樹的性能

所以需要進行調節

分爲三種情況

第一種情況

插入的紅色節點Z 其父節點的兄弟節點即叔節點也是紅色

那麼將z節點的父節點和叔節點都改爲黑色  z節點的父節點的父節點改爲紅色

Z節點設置爲z節點的父節點的父節點 再次進行調整FIXUP


y是z的叔節點 紅色 

那麼 將 5號節點 、8號節點(y)改黑 7號改紅 

z節點爲7號節點 再次進行判斷調整

 

第二種情況和第三種情況類似

z的叔節點y是黑色的 且z節點是右孩子

z的叔節點y是黑色的 且z節點是左孩子


調整的僞代碼和代碼如下:


void RBInsertFixup(std::shared_ptr<node>& root, std::shared_ptr<node> z) {
    while (z->parent_->color_ == red) {   //插入節點Z是紅色 若Z父節點也是紅色則需要調整
        if (z->parent_ == z->parent_->parent_->left_){  // 父節點是左子樹的情況
            std::shared_ptr<node> y = z->parent_->parent_->right_;
            if (y->color_ == red){                   //  情況1
                z->parent_->color_ = black;
                y->color_ = black;
                z->parent_->parent_->color_ = red;
                z = z->parent_->parent_;
            }
            else {
                if (z == z->parent_->right_) {
                    z = z->parent_;                  //  情況2
                    LeftRotate(root, z);
                }
                z->parent_->color_ = black;           //  情況3
                z->parent_->parent_->color_ = red;
                RightRotate(root, z->parent_->parent_);
            }
        }
        else {// 父節點是右子樹的情況 與上面判斷處理均是鏡像對稱
            std::shared_ptr<node> y = z->parent_->parent_->left_;
            if (y->color_ == red){
                z->parent_->color_ = black;
                y->color_ = black;
                z->parent_->parent_->color_ = red;
                z = z->parent_->parent_;
            }
            else {
                if (z == z->parent_->left_) {
                    z = z->parent_;
                    RightRotate(root, z);
                }
                z->parent_->color_ = black;
                z->parent_->parent_->color_ = red;
                LeftRotate(root, z->parent_->parent_);
            }
        }  
    }//while (z->parent_->color_ == red)
    root->color_ = black;
}//function end

下面是全部代碼

// rbTreeTest.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"
#include <memory>
#include <iostream>

using namespace std;

enum Color {
	red = 1,
	black
};

struct node {
	Color color_;
	std::shared_ptr<node> left_;
	std::shared_ptr<node> right_;
	std::shared_ptr<node> parent_;
	int value_;
	node() {
		left_ = right_ = parent_ = nullptr;
		value_ = -1;
		color_ = black;
	}
};

std::shared_ptr<node> nil(new node);


std::shared_ptr<node> CreateNode(Color color, int i) {
	std::shared_ptr<node> p(new node);
	p->color_ = color;
	p->left_ = nil;
	p->right_ = nil;
	p->parent_ = nil;
	p->value_ = i;
	return p;
}

void RightRotate(std::shared_ptr<node>& root, std::shared_ptr<node> x) {
	std::shared_ptr<node> y = x->left_;
	x->left_ = y->right_;
	if (y->right_ != nil)
		y->right_->parent_ = x;
	y->parent_ = x->parent_;
	if (x->parent_ == nil) {
		root = y;
	}
	else if (x->parent_->left_ == x) {
		x->parent_->left_ = y;
	}
	else {
		x->parent_->right_ = y;
	}

	y->right_ = x;
	x->parent_ = y;
}

void LeftRotate(std::shared_ptr<node>& root, std::shared_ptr<node> x) {
	std::shared_ptr<node> y = x->right_;
	x->right_ = y->left_;
	if (y->left_ != nil)
		y->left_->parent_ = x;

	y->parent_ = x->parent_;
	if (x->parent_ == nil) {
		root = y;
	}
	else if (x->parent_->left_ == x) {
		x->parent_->left_ = y;
	}
	else {
		x->parent_->right_ = y;
	}
	y->left_ = x;
	x->parent_ = y;
}

void PrinTree(std::shared_ptr<node> root) {
	if (root == nil) {
		std::cout << "nil:" << ":color-" << root->color_ << " ; " << std::endl << std::endl;
		return;
	}
	std::cout << root->value_ << ":color-" << root->color_ << "; address:" << root << std::endl;
	if (root->parent_ == nil) {
		std::cout << "parent_:" << "nil" << std::endl;
	}
	else {
		std::cout << "parent_:" << root->parent_ << std::endl;
	}

	if (root->left_ == nil) {
		std::cout << "left_:" << "nil" << std::endl;
	}
	else {
		std::cout << "left_:" << root->left_ << std::endl;
	}


	if (root->right_ == nil) {
		std::cout << "right_:" << "nil" << std::endl;
	}
	else {
		std::cout << "right_:" << root->right_ << std::endl;
	}

	std::cout << std::endl;


	if (root->left_ != nil)
		PrinTree(root->left_);
	if (root->right_ != nil)
		PrinTree(root->right_);
}

void RBInsertFixup(std::shared_ptr<node>& root, std::shared_ptr<node> z) {
	while (z->parent_->color_ == red) {   //插入節點Z是紅色 若Z父節點也是紅色則需要調整
		if (z->parent_ == z->parent_->parent_->left_) {  // 父節點是左子樹的情況
			std::shared_ptr<node> y = z->parent_->parent_->right_;
			if (y->color_ == red) {                   //  情況1
				z->parent_->color_ = black;
				y->color_ = black;
				z->parent_->parent_->color_ = red;
				z = z->parent_->parent_;
			}
			else {
				if (z == z->parent_->right_) {
					z = z->parent_;                  //  情況2
					LeftRotate(root, z);
				}
				z->parent_->color_ = black;           //  情況3
				z->parent_->parent_->color_ = red;
				RightRotate(root, z->parent_->parent_);
			}
		}
		else {// 父節點是右子樹的情況 與上面判斷處理均是鏡像對稱
			std::shared_ptr<node> y = z->parent_->parent_->left_;
			if (y->color_ == red) {
				z->parent_->color_ = black;
				y->color_ = black;
				z->parent_->parent_->color_ = red;
				z = z->parent_->parent_;
			}
			else {
				if (z == z->parent_->left_) {
					z = z->parent_;
					RightRotate(root, z);
				}
				z->parent_->color_ = black;
				z->parent_->parent_->color_ = red;
				LeftRotate(root, z->parent_->parent_);
			}
		}
	}//while (z->parent_->color_ == red)
	root->color_ = black;
}//function end

void RBInsert(std::shared_ptr<node>& root, std::shared_ptr<node> ins) {
	std::shared_ptr<node> y = nil;
	std::shared_ptr<node> x = root;

	while (x != nil) {
		y = x;
		if (ins->value_ < x->value_) {
			x = x->left_;
		}
		else {
			x = x->right_;
		}
	}
	ins->parent_ = y;
	if (y == nil) {
		root = ins;
	}
	else if (ins->value_ < y->value_) {
		y->left_ = ins;
	}
	else {
		y->right_ = ins;
	}
	ins->left_ = ins->right_ = nil;
	ins->color_ = red;
	// todo  fixup
	RBInsertFixup(root,ins);
}

void TestInsert() {
	std::shared_ptr<node> root = nil;
	std::shared_ptr<node> x = CreateNode(red, 7);
	RBInsert(root, x);


	x = CreateNode(red, 4);
	RBInsert(root, x);

	x = CreateNode(red, 11);
	RBInsert(root, x);

	x = CreateNode(red, 3);
	RBInsert(root, x);

	x = CreateNode(red, 6);
	RBInsert(root, x);

	x = CreateNode(red, 9);
	RBInsert(root, x);

	x = CreateNode(red, 18);
	RBInsert(root, x);

	x = CreateNode(red, 2);
	RBInsert(root, x);

	x = CreateNode(red, 14);
	RBInsert(root, x);

	x = CreateNode(red, 19);
	RBInsert(root, x);

	x = CreateNode(red, 12);
	RBInsert(root, x);

	x = CreateNode(red, 17);
	RBInsert(root, x);

	x = CreateNode(red, 22);
	RBInsert(root, x);

	x = CreateNode(red, 20);
	RBInsert(root, x);
	PrinTree(root);
	std::cout << std::endl;
}

int main()
{
	TestInsert();

	return 0;
}




運行效果



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