您的位置:首页 > 其它

算法导论 红黑树 学习 插入(三)

2017-02-14 19:26 218 查看
学习算法 还是建议看看算法导论

算法导论第三版 如果不看数学推导 仅看伪代码 难度还是适中

本系列只是记录我的学习心得 和伪代码转化代码的过程

深入学习 还是建议大家看看算法书籍 教程更加系统。

本文参考算法导论第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;
}

运行效果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法导论 红黑树