RedBlack-Tree(红黑树)原理及C++代码实现
众所周知,红黑树是用途很广的平衡二叉搜索树,用过的都说好。所以我们来看看红黑树的是怎么实现的吧。
红黑树顾名思义,通过红与黑两种颜色来给每个节点上色。其中根结点和叶子结点一定是黑色的,并且红色结点的两个孩子一定是黑色的,每个结点到所有后代叶子的简单路径上,均包含相同数目的黑色结点(黑高bh)。
这里和其他树有些区别的是,红黑树的叶子结点并不包含关键字,它只是用来维持红黑树的性质。所以包含关键字的结点都是内部结点。
这样的性质也带来了很多有意思的现象。下面我们忽略所谓的叶子结点来看看。
1.红色结点的孩子要么没有,要么是两个黑色结点,不会有单个孩子结点的时候。
2.如果某个结点只有一个孩子结点,那么那个孩子结点一定是红色的。
3.用吸收的角度去看,即黑色结点可以吸收它的红色孩子结点,红黑树就像一个2-3-4树。
下面我们来看看代码吧,代码用了一个小技巧,即所有的叶子结点都用一个nil结点来表示,指向nullptr的指针现在全部指向nil。
代码如下:(仅供参考)
- #include <iostream>
- using namespace std;
- class RBT {
- private :
- enum {RED = , BLACK};
- struct Node {
- int key;
- bool color;
- Node * left;
- Node * right;
- Node * parent;
- Node(int k = , bool c = BLACK, Node *l = nullptr, Node *r = nullptr, Node *p = nullptr)
- : key(k), color(c), left(l), right(r), parent(p) {}
- };
- private :
- Node * nil;
- Node * root;
- private :
- void leftRotate(Node * x);
- void rightRotate(Node * x);
- void fixup_insert(Node * p);
- void fixup_remove(Node * p);
- void transplant(Node * old_t, Node * new_t);
- void insert(Node * p);
- void remove(Node * p);
- Node * search(Node * p, const int k);
- Node * minimum(Node * p);
- Node * maximum(Node * p);
- void inorderWalk(Node * p) const;
- public :
- RBT() : nil(new Node), root(nil) {}
- ~RBT() {delete nil;}
- void insert(const int key) {insert(new Node(key, RED, nil, nil, nil));}
- void remove(const int key) {remove(search(root, key));}
- bool search(const int key) {return (search(root, key) == nil ? false : true);}
- int minimum() {return minimum(root)->key;}
- int maximum() {return maximum(root)->key;}
- int predecessor(const int key);
- int successor(const int key);
- friend ostream &operator<<(ostream &os, const RBT &t);
- };
- void RBT::inorderWalk(Node * p) const {
- if (p != nil) {
- inorderWalk(p->left);
- cout << p->key << ' ';
- inorderWalk(p->right);
- }
- }
- RBT::Node * RBT::search(Node * p, const int k) {
- if (p == nil || k == p->key)
- return p;
- if (k < p->key)
- return search(p->left, k);
- else
- return search(p->right, k);
- }
- RBT::Node * RBT::minimum(Node * p) {
- if (p == nil)
- return p;
- while (p->left != nil)
- p = p->left;
- return p;
- }
- RBT::Node * RBT::maximum(Node * p) {
- if (p == nil)
- return p;
- while (p->right != nil)
- p = p->right;
- return p;
- }
- int RBT::predecessor(const int k) {
- Node * p = search(root, k);
- if (p == nil)
- return ;
- if (p->left != nil)
- return maximum(p->left)->key;
- Node * y = p->parent;
- while (y != nil && y->left == p) {
- p = y;
- y = y->parent;
- }
- return y->key;
- }
- int RBT::successor(const int k) {
- Node * p = search(root, k);
- if (p == nil)
- return ;
- if (p->right != nil)
- return minimum(p->right)->key;
- Node * y = p->parent;
- while (y != nil && y->right == p) {
- p = y;
- y = y->parent;
- }
- return y->key;
- }
- void RBT::leftRotate(Node * x) { //assume:x->right != nil
- 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 == x->parent->left)
- x->parent->left = y;
- else
- x->parent->right = y;
- y->left = x;
- x->parent = y;
- }
- void RBT::rightRotate(Node * x) { //assume:x->left != nil
- 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 == x->parent->right)
- x->parent->right = y;
- else
- x->parent->left = y;
- y->right = x;
- x->parent = y;
- }
- void RBT::insert(Node * p) {
- if (p == nullptr)
- return ;
- Node * x = root;
- Node * y = nil;
- while (x != nil) {
- y = x;
- if (x->key < p->key)
- x = x->right;
- else
- x = x->left;
- }
- p->parent = y;
- if (y == nil)
- root = p;
- else if (y->key < p->key)
- y->right = p;
- else
- y->left = p;
- fixup_insert(p);
- }
- void RBT::fixup_insert(Node * p) {
- while (p->parent->color == RED) {
- if (p->parent == p->parent->parent->left) {
- Node * y = p->parent->parent->right;
- if (y->color == RED) { //case 1
- p->parent->color = BLACK;
- y->color = BLACK;
- p->parent->parent->color = RED;
- p = p->parent->parent;
- }
- else {
- if (p == p->parent->right) { //case 2
- p = p->parent;
- leftRotate(p);
- }
- p->parent->color = BLACK; //case 3
- p->parent->parent->color = RED;
- rightRotate(p->parent->parent);
- }
- }
- else { //with "right" and "left" exchanged
- Node * y = p->parent->parent->left;
- if (y->color == RED) { //case 1
- p->parent->color = BLACK;
- y->color = BLACK;
- p->parent->parent->color = RED;
- p = p->parent->parent;
- }
- else {
- if (p == p->parent->left) { //case 2
- p = p->parent;
- rightRotate(p);
- }
- p->parent->color = BLACK; //case 3
- p->parent->parent->color = RED;
- leftRotate(p->parent->parent);
- }
- }
- }
- root->color = BLACK;
- }
- void RBT::transplant(Node * old_t, Node * new_t) {
- if (old_t->parent == nil)
- root = new_t;
- else if (old_t == old_t->parent->left)
- old_t->parent->left = new_t;
- else
- old_t->parent->right = new_t;
- new_t->parent = old_t->parent;
- }
- void RBT::fixup_remove(Node * x) {
- Node * z = nil;
- while (x != root && x->color == BLACK) {
- if (x == x->parent->left) {
- z = x->parent->right;
- /*case 1*/ if (z->color == RED) {
- z->color = BLACK;
- x->parent->color = RED;
- leftRotate(x->parent);
- z = x->parent->right; //new z
- }
- /*case 2*/ if (z->left->color == BLACK && z->right->color == BLACK) {
- z->color = RED;
- x = x->parent;
- }
- else {
- /*case 3*/ if (z->right->color == BLACK) {
- z->left->color = BLACK;
- z->color = RED;
- rightRotate(z);
- z = x->parent->right;
- }
- /*case 4*/ z->color = x->parent->color;
- x->parent->color = BLACK;
- z->right->color = BLACK;
- leftRotate(x->parent);
- x = root; //exit while
- }
- }
- else {
- z = x->parent->left;
- /*case 1*/ if (z->color == RED) {
- z->color = BLACK;
- x->parent->color = RED;
- rightRotate(x->parent);
- z = x->parent->left; //new z
- }
- /*case 2*/ if (z->right->color == BLACK && z->left->color == BLACK) {
- z->color = RED;
- x = x->parent;
- }
- else {
- /*case 3*/ if (z->left->color == BLACK) {
- z->right->color = BLACK;
- z->color = RED;
- leftRotate(z);
- z = x->parent->left;
- }
- /*case 4*/ z->color = x->parent->color;
- x->parent->color = BLACK;
- z->left->color = BLACK;
- rightRotate(x->parent);
- x = root; //exit while
- }
- }
- }
- x->color = BLACK;
- }
- void RBT::remove(Node * p) {
- if (p == nil)
- return ;
- Node * y = p;
- Node * x = nil;
- bool y_originalColor = y->color;
- if (p->left == nil) {
- x = p->right;
- transplant(p, p->right);
- }
- else if (p->right == nil) {
- x = p->left;
- transplant(p, p->left);
- }
- else {
- y = minimum(p->right);
- y_originalColor = y->color;
- x = y->right;
- if (y->parent == p)
- x->parent = y; //maybe x == nil
- else {
- transplant(y, y->right);
- y->right = p->right;
- y->right->parent = y;
- }
- transplant(p, y);
- y->left = p->left;
- y->left->parent = y;
- y->color = p->color;
- }
- delete p;
- if (y_originalColor == BLACK)
- fixup_remove(x);
- }
- ostream &operator<<(ostream &os, const RBT &t) {
- t.inorderWalk(t.root);
- return os;
- }
RedBlack-Tree(红黑树)原理及C++代码实现的更多相关文章
- 红黑树原理详解及golang实现
目录 红黑树原理详解及golang实现 二叉查找树 性质 红黑树 性质 operation 红黑树的插入 golang实现 类型定义 leftRotate RightRotate Item Inter ...
- Java面试题之红黑树原理
红黑树原理: 每个节点都只能是红色或黑色的: 根节点是黑色的: 每个叶节点(空节点)是黑色的: 如果一个节点是红色的,那么他的子节点都是黑色的: 从任意一个节点到其每个子节点的路径都有相同数目的黑色节 ...
- Red Black Tree 红黑树 AVL trees 2-3 trees 2-3-4 trees B-trees Red-black trees Balanced search tree 平衡搜索树
小结: 1.红黑树:典型的用途是实现关联数组 2.旋转 当我们在对红黑树进行插入和删除等操作时,对树做了修改,那么可能会违背红黑树的性质.为了保持红黑树的性质,我们可以通过对树进行旋转,即修改树中某些 ...
- 从二叉查找树到平衡树:avl, 2-3树,左倾红黑树(含实现代码),传统红黑树
参考:自平衡二叉查找树 ,红黑树, 算法:理解红黑树 (英文pdf:红黑树) 目录 自平衡二叉树介绍 avl树 2-3树 LLRBT(Left-leaning red-black tree左倾红黑树 ...
- HashMap1.7和1.8,红黑树原理!
jdk 1.7 概述 HashMap基于Map接口实现,元素以键值对的方式存储,并允许使用null键和null值,但只能有一个键作为null,因为key不允许重复,另外HashMap不能保证放入元素的 ...
- 排序二叉树、平衡二叉树、红黑树、B+树
一.排序二叉树(Binary Sort Tree,BST树) 二叉排序树,又叫二叉搜索树.有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree). 1 ...
- AVL树、splay树(伸展树)和红黑树比较
AVL树.splay树(伸展树)和红黑树比较 一.AVL树: 优点:查找.插入和删除,最坏复杂度均为O(logN).实现操作简单 如过是随机插入或者删除,其理论上可以得到O(logN)的复杂度,但是实 ...
- 第十四章 红黑树——C++代码实现
红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树.红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键 ...
- 红黑树 - C++代码实现
红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树.红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键 ...
- 红黑树插入与删除完整代码(dart语言实现)
之前分析了红黑树的删除,这里附上红黑树的完整版代码,包括查找.插入.删除等.删除后修复实现了两种算法,均比之前的更为简洁.一种是我自己的实现,代码非常简洁,行数更少:一种是Linux.Java等源码版 ...
随机推荐
- consul集群配置
consul agent -server -bootstrap-expect 1 -data-dir /etc/consul -node=consul1 -bind=ip1 -ui -client=0 ...
- cf1208 D Restore Permutation (二分+树状数组)
题意 让你构造一个长度为n的序列,记为p1……pn,(这个序列是1~n的全排列的一种) 给你n个数,记为s1……sn,si的值为p1……pi-1中小于pi的数的和. 思路 显然,应该倒着来,也就是从p ...
- python clickZan
import pyautogui,time,random pyautogui.PAUSE = 3 pyautogui.FAILSAFE = True width, height = pyautogui ...
- 日志处理中一些shell命令技巧
日志处理中一些shell命令技巧 阴差阳错的做的日志分析,前途未卜的这段日子,唯一还有点意思的可能就是手动的处理大量日志.总结一下. 日志文件的输入是动则几个G的文本.从N个这样的文件中得到一个列表, ...
- jenkins+saltstack+pipeline 部署springcloud 多模块jar包
在jenkins上安装salt-master, pipeline{ agent{ node{ label 'master' cust ...
- spring aop中的propagation的7种配置
1.前言 在声明式的事务处理中,要配置一个切面,即一组方法,如 <tx:advice id="txAdvice" transaction-manager="txMa ...
- 18 11 13 装了ssd 继续 网络通信 tcp 客户端的创建
import socket def main(): # 1. 买个手机(创建套接字 socket) 联通公司建立了一个信号塔 tcp_server_socket = socket.socket(soc ...
- CENTOS YUM更新源
网络yum源和制作本地光盘yum源 配置CENTOS YUM更新源 yum安装rpm包安装后本地不清除的方法 sed -i 's#keepcache=0#keepcache=1#g' /etc/yum ...
- ubuntu下git的使用
1.安装git sudo apt-get install git sudo apt-get install git-core 2.配置git lzb@lzb:~$ git config --globa ...
- Scala(一)——scala+Idea环境配置
Java虚拟机的确是很强大,有很多计算机语言可以运行在虚拟机上,完善了虚拟机上多语言编程. 近年来,大数据云计算,大数据的火爆也让一些小众语言火了起来,如Python,Scala等.这些语言编写简单, ...