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

来源:互联网 发布:礼品卡兑换系统源码 编辑:程序博客网 时间:2024/04/30 08:14

学习算法 还是建议看看算法导论

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

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

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

本文参考算法导论第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) {                   //  情况1z->parent_->color_ = black;y->color_ = black;z->parent_->parent_->color_ = red;z = z->parent_->parent_;}else {if (z == z->parent_->right_) {z = z->parent_;                  //  情况2LeftRotate(root, z);}z->parent_->color_ = black;           //  情况3z->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 endvoid 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  fixupRBInsertFixup(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;}




运行效果



0 0
原创粉丝点击