众所周知,红黑树是用途很广的平衡二叉搜索树,用过的都说好。所以我们来看看红黑树的是怎么实现的吧。

红黑树顾名思义,通过红与黑两种颜色来给每个节点上色。其中根结点和叶子结点一定是黑色的,并且红色结点的两个孩子一定是黑色的,每个结点到所有后代叶子的简单路径上,均包含相同数目的黑色结点(黑高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++代码实现的更多相关文章

  1. 红黑树原理详解及golang实现

    目录 红黑树原理详解及golang实现 二叉查找树 性质 红黑树 性质 operation 红黑树的插入 golang实现 类型定义 leftRotate RightRotate Item Inter ...

  2. Java面试题之红黑树原理

    红黑树原理: 每个节点都只能是红色或黑色的: 根节点是黑色的: 每个叶节点(空节点)是黑色的: 如果一个节点是红色的,那么他的子节点都是黑色的: 从任意一个节点到其每个子节点的路径都有相同数目的黑色节 ...

  3. Red Black Tree 红黑树 AVL trees 2-3 trees 2-3-4 trees B-trees Red-black trees Balanced search tree 平衡搜索树

    小结: 1.红黑树:典型的用途是实现关联数组 2.旋转 当我们在对红黑树进行插入和删除等操作时,对树做了修改,那么可能会违背红黑树的性质.为了保持红黑树的性质,我们可以通过对树进行旋转,即修改树中某些 ...

  4. 从二叉查找树到平衡树:avl, 2-3树,左倾红黑树(含实现代码),传统红黑树

    参考:自平衡二叉查找树 ,红黑树, 算法:理解红黑树 (英文pdf:红黑树) 目录 自平衡二叉树介绍 avl树 2-3树 LLRBT(Left-leaning red-black tree左倾红黑树 ...

  5. HashMap1.7和1.8,红黑树原理!

    jdk 1.7 概述 HashMap基于Map接口实现,元素以键值对的方式存储,并允许使用null键和null值,但只能有一个键作为null,因为key不允许重复,另外HashMap不能保证放入元素的 ...

  6. 排序二叉树、平衡二叉树、红黑树、B+树

    一.排序二叉树(Binary Sort Tree,BST树) 二叉排序树,又叫二叉搜索树.有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree). 1 ...

  7. AVL树、splay树(伸展树)和红黑树比较

    AVL树.splay树(伸展树)和红黑树比较 一.AVL树: 优点:查找.插入和删除,最坏复杂度均为O(logN).实现操作简单 如过是随机插入或者删除,其理论上可以得到O(logN)的复杂度,但是实 ...

  8. 第十四章 红黑树——C++代码实现

    红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树.红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键 ...

  9. 红黑树 - C++代码实现

    红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树.红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键 ...

  10. 红黑树插入与删除完整代码(dart语言实现)

    之前分析了红黑树的删除,这里附上红黑树的完整版代码,包括查找.插入.删除等.删除后修复实现了两种算法,均比之前的更为简洁.一种是我自己的实现,代码非常简洁,行数更少:一种是Linux.Java等源码版 ...

随机推荐

  1. HZNU-ACM寒假集训Day6小结 线性DP

    线性DP 考虑一组硬币面值 1,5,11 给定W,求凑出W的最少硬币个数 我们记凑出n需要用到的最少硬币数量为f(n)   我们注意到了一个很棒的性质 : f(n)只与f(n-1) f(n-5) f( ...

  2. 关于indexOf的用法

     var fullTaskName = this.form.taskName;       var index=fullTaskName.lastIndexOf("-");     ...

  3. cf 1241 E. Paint the Tree(DP)

    题意: 有一颗树,n个点,边有边权. 有无限多种颜色,每个点可以同时染上k种颜色,如果一条边的两个端点 拥有至少一种相同的颜色,那么说这条边是“饱和的”. 问:所有“饱和边”的权值和最大为多少,只需要 ...

  4. python控制鼠标键盘

    1.安装类库 pip install pyautogui 2.代码: import pyautogui,time,random pyautogui.PAUSE = pyautogui.FAILSAFE ...

  5. 阿里云服务器搭建详解——Ubuntu

    由于自己电脑配置跟不上,双系统一开,整个电脑就会变得非常卡顿,所以决定在阿里云买一个云服务器.听朋友说,学生买的话是非常便宜的,比每月开个SVIP还便宜.今天上网看了下,果然如此,每月只要9.9,确实 ...

  6. SpringCloud学习之Ribbon使用(四)

    1.关于 Ribbon Spring Cloud Ribbon 是基于 Netflix Ribbon 实现的一套客户端负载均衡的工具.Ribbon 是 Netflix 发布的开源项目,主要功能是提供客 ...

  7. JetBrains系列-插件

       插件官网:http://plugins.jetbrains.com   注意:网站有时不稳定,会造成打不开,属正常现象或许下一秒就好了,可以选择去git等方式下载 1.安装说明:   打开fil ...

  8. 简单LCS HDU_1503

    学了一下最长公共子串,它是属于dp里面的 dp=max{(i,j-1),(i-1,j),(i-1,j-1)+d}问题,不得不说,规划方向确实厉害,当然这只适用于两个字符串匹配的问题,n个字符串的话,我 ...

  9. 【转帖】使用容器化和 Docker 实现 DevOps 的基础知识

    使用容器化和 Docker 实现 DevOps 的基础知识 https://www.kubernetes.org.cn/6730.html 2020-02-24 15:20 灵雀云 分类:容器 阅读( ...

  10. java笔记-手写