• 算法导论 红黑树 学习 旋转(二)图文


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

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

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

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

    本文参考算法导论第13章节 红黑树

    代码由本人写成

    转载请标明出处

    红黑树是一个带颜色的二叉树

    有以下5点性能

    1 每个节点或者红色或者黑色

    2 根节点黑色

    3 每个叶子节点(nil)为黑色

    4 如果一个节点是红色的则它的两个子节点都是黑色

    5 每个节点 该节点到子孙节点的路径上 黑色节点数目相同

    如图

    nil节点共享版本

    隐藏nil节点

    红黑树的结构与二叉树类似

    但是增加了指向节点父节点的指针 和颜色记录

    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;
        }
    };
    

      

    还创建以叶节点nil

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

    打印函数 与二叉树变化不大

    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_);
    }

    旋转操作

    旋转是保持平衡的最基本的操作 我们先从这里开始学习

    在实际的操作旋转如图

    伪代码如图

    实际上就是

    将Y的左子树 更改为X的右子树

    X更改为Y的左子树

    实际代码为

    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;
    }
    

     我们来创建一个红黑树 测试下旋转操作(先不关注颜色 只关注旋转操作)

    全部代码如下

    // rbShow.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) {
    		return;
    	}
    	std::cout << root->value_ << " ";
    	if (root->left_ != nil)
    		PrinTree(root->left_);
    	if (root->right_ != nil)
    		PrinTree(root->right_);
    }
    
    void TestLeftRotate1() {
    	std::shared_ptr<node> root = CreateNode(black, 1);
    	root->parent_ = nil;
    	std::shared_ptr<node> x = root;
    	root->right_ = CreateNode(red, 2);
    	root->right_->parent_ = root;
    
    
    	PrinTree(root);
    	std::cout << std::endl;
    	LeftRotate(root, x);
    	PrinTree(root);
    	std::cout << std::endl;
    }
    
    void TestRightRotate1() {
    	std::shared_ptr<node> root = CreateNode(black, 2);
    	root->parent_ = nil;
    	std::shared_ptr<node> x = root;
    	std::shared_ptr<node> y = CreateNode(red, 1);
    	root->left_ = y;
    	y->parent_ = x;
    
    	PrinTree(root);
    	std::cout << std::endl;
    	RightRotate(root, x);
    	PrinTree(root);
    	std::cout << std::endl;
    }
    
    
    int main()
    {
    	TestLeftRotate1();
    	TestRightRotate1();
        return 0;
    }
    

    代码运行效果如图

      

    由于左旋转与右旋转 是镜像映射的 这里仅仅介绍左旋转

    左旋转后

    再来一个多节点的旋转

    // rbShow.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) {
    		return;
    	}
    	std::cout << root->value_ << " ";
    	if (root->left_ != nil)
    		PrinTree(root->left_);
    	if (root->right_ != nil)
    		PrinTree(root->right_);
    }
    
    void TestLeftRotate2() {
    	//测试 1 3 2 4
    	std::shared_ptr<node> root = CreateNode(black, 1);
    	root->parent_ = nil;
    
    	root->right_ = CreateNode(red, 3);
    	root->right_->parent_ = root;
    
    	std::shared_ptr<node> x = root->right_;
    
    	std::shared_ptr<node> y = CreateNode(red, 2);
    	x->left_ = y;
    	y->parent_ = x;
    
    	std::shared_ptr<node> z = CreateNode(red, 4);
    	x->right_ = z;
    	z->parent_ = x;
    
    	PrinTree(root);
    	std::cout << std::endl;
    
    	LeftRotate(root, x);
    	PrinTree(root);
    	std::cout << std::endl;
    }
    
    void TestRightRotate1() {
    	//测试 9 10 6 8 4 2 5
    	std::shared_ptr<node> root = CreateNode(black, 9);
    	root->parent_ = nil;
    	std::shared_ptr<node> a = root;
    
    	std::shared_ptr<node> b = CreateNode(black, 10);
    	a->right_ = b;
    	b->parent_ = a;
    
    	std::shared_ptr<node> c = CreateNode(black, 6);
    	a->left_ = c;
    	c->parent_ = a;
    
    	std::shared_ptr<node> d = CreateNode(black, 8);
    	c->right_ = d;
    	d->parent_ = c;
    
    	std::shared_ptr<node> e = CreateNode(black, 4);
    	c->left_ = e;
    	e->parent_ = c;
    
    	std::shared_ptr<node> f = CreateNode(black, 2);
    	e->left_ = f;
    	f->parent_ = e;
    
    	std::shared_ptr<node> g = CreateNode(black, 5);
    	e->right_ = g;
    	g->parent_ = e;
    
    	PrinTree(root);
    	std::cout << std::endl;
    
    	RightRotate(root, c);
    
    	PrinTree(root);
    	std::cout << std::endl;
    }
    
    
    int main()
    {
    	TestLeftRotate1();
    	std::cout << std::endl;
    	TestRightRotate1();
        return 0;
    }
    

     这里介绍右旋转 图示如图

    节点6进行右旋转后

    作 者: itdef
    欢迎转帖 请保持文本完整并注明出处
    技术博客 http://www.cnblogs.com/itdef/
    B站算法视频题解
    https://space.bilibili.com/18508846
    qq 151435887
    gitee https://gitee.com/def/
    欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    Oracel基础知识
    64位系统运行32位Oracle程序解决方案
    Oracle 级联删除
    string转DateTime(时间格式转换)
    vs2013 内置IIS Express相关问题
    小马哥课堂-统计学-置信区间(2)
    小马哥课堂-统计学-置信区间
    小马哥课堂-统计学-标准误差
    小马哥课堂-统计学-中心极限定理
    python之histogram
  • 原文地址:https://www.cnblogs.com/itdef/p/6395240.html
Copyright © 2020-2023  润新知