學習算法 還是建議看看算法導論
算法導論第三版 如果不看數學推導 僅看僞代碼 難度還是適中
本系列只是記錄我的學習心得 和僞代碼轉化代碼的過程
深入學習 還是建議大家看看算法書籍 教程更加系統。
本文參考算法導論第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;
}