更多文章见C++面试题系列

产生背景:

红黑树解决了平衡二叉树为了重新维持平衡旋转成本太高的问题.

平衡二叉树又称AVLTree,平衡二叉树最大的作用是查找,因为AVL树的查找,插入和删除在平均和最坏情况小都是O(logn)?

红黑树与AVL树比较:

1.插入删除操作,红黑树更容易控制;

2.旋转操作,调整平衡时红黑树的旋转次数更少.

红黑树性质和定义:

红黑树(Red-Black Tree)又称RB Tree,它是一个二叉查找树(二叉搜索树)?,每个节点包含一个存储为来表示节点的颜色,节点的颜色可以是红色或者黑色.一棵红黑树具有如下性质:

1.每个节点的颜色不是红色就是黑色

2.根节点的颜色是黑色

3.叶子节点(NULL)的颜色是黑色

4.每个红色节点,它的子节点必须是黑色

5.一个节点到该节点所有子孙节点的路径包含相同的黑色节点数,该性质保证最大路径长度不会超过最小路径长度的2倍,从而保证红黑树是一颗近似平衡二叉树.

定义红黑树节点:

enum RBTColor{RED, BLACK};template <class T>
class RBTNode {
public:RBTColor color;T key;RBTNode *left;RBTNode *right;RBTNode *parent;RBTNode(T val, RBTColor col, RBTNode *p, RBTNode *l,RBTNode *r):key(val),color(col),parent(p),left(l),right(r){}
};

红黑树操作:

1.左旋和右旋

对红黑树进行插入或删除操作后,该红黑树可能不再满足红黑树的5个基本性质,为了保持红黑树的特性,需要对该树进行旋转操作.

常见的旋转操作包括:左旋和右旋.

1.左旋

对x节点进行左旋,就是让X节点旋转后成为一个左孩子,成为它右孩子的左孩子.

下面再看1个例子:

例子1:

总结,左旋操作可以分三步走:

(1)移动y的左孩子,y的左孩子移动为X的右孩子。X的右孩子指向y的左孩子,y的左孩子的父节点指向X.

(2)移动y节点,y的父节点指向X的父节点,如果X不是根节点,X父节点的左孩子或右孩子指向Y.。如果X是根节点则,y设置为根节点

(3)移动X节点,y节点的左孩子指向X,X的父节点指向Y.

实现代码:

/*
* 对红黑树的节点(x)进行左旋转
*
* 左旋示意图(对节点x进行左旋):
*      px                              px
*     /                               /
*    x                               y
*   /  \      --(左旋)-->           / \                #
*  lx   y                          x  ry
*     /   \                       /  \
*    ly   ry                     lx  ly
*
*
*/
template<class T>
void CMyRBTree<T>::leftRotate(RBTNode<T>*& root, RBTNode<T>* x)
{//定义一个指针y,指向x的右孩子;RBTNode<T> *y = x->right;//1.将"y的左孩子"设为"X的右孩子"x->right = y->left;if (y->left != nullptr){y->left->parent = x;}//2.将"X的父节点"设为"Y的父节点"y->parent = x->parent;if (x->parent == nullptr){root = y;}else{if (x->parent->left == x){x->parent->left = y;}else {x->parent->right = y;}}//3.将x作为y的左孩子y->left = x;x->parent = y;}

2.右旋

假设右旋节点为y,y的左孩子为x。右旋就是让y成为它的左孩子的有孩子

1.移动y节点的左孩子的右孩子,这里是beta,beta变为y节点的左孩子

2.移动y节点的左孩子,这里是X,X的父亲节点指向y的父亲节点

如果y的父亲节点为空,则root==x

如果y->parent->left==y,则y->parent->left=x;

如果y->parent->right==y,则y->parent->right=x

3.移动y节点,y->parent=x;x->right=y;

/* * 对红黑树的节点(y)进行右旋转** 右旋示意图(对节点y进行左旋):*            py                               py*           /                                /*          y                                x                  *         /  \      --(右旋)-->            /  \                     #*        x   ry                           lx   y  *       / \                                   / \                   #*      lx  rx                                rx  ry* */
template <class T>
void RBTree<T>::rightRotate(RBTNode<T>* &root, RBTNode<T>* y)
{// 设置x是当前节点的左孩子。RBTNode<T> *x = y->left;// 将 “x的右孩子” 设为 “y的左孩子”;// 如果"x的右孩子"不为空的话,将 “y” 设为 “x的右孩子的父亲”y->left = x->right;if (x->right != NULL)x->right->parent = y;// 将 “y的父亲” 设为 “x的父亲”x->parent = y->parent;if (y->parent == NULL) {root = x;            // 如果 “y的父亲” 是空节点,则将x设为根节点}else{if (y == y->parent->right)y->parent->right = x;    // 如果 y是它父节点的右孩子,则将x设为“y的父节点的右孩子”elsey->parent->left = x;    // (y是它父节点的左孩子) 将x设为“x的父节点的左孩子”}// 将 “y” 设为 “x的右孩子”x->right = y;// 将 “y的父节点” 设为 “x”y->parent = x;
}

牛客网:C++校招面试题合集

269:请问红黑树了解吗

270:请你说一说红黑树的性质还有左右旋转

271:请你说一说红黑树的原理以及erase以后迭代器的具体分布情况?

https://bbs.csdn.net/topics/350253651/

参考文献:

红黑树原理

红黑树C++实现

附件:源代码

.h

#pragma onceenum RBTColor{RED, BLACK};template <class T>
class RBTNode {
public:RBTColor color;T key;RBTNode *left;RBTNode *right;RBTNode *parent;RBTNode(T val, RBTColor col, RBTNode *p, RBTNode *l,RBTNode *r):key(val),color(col),parent(p),left(l),right(r){}
};template <class T>
class CMyRBTree
{
private://跟节点RBTNode<T> *mRoot;
public:CMyRBTree();~CMyRBTree();// 前序遍历"红黑树"void preOrder();// 中序遍历"红黑树"void inOrder();// 后序遍历"红黑树"void postOrder();// (递归实现)查找"红黑树"中键值为key的节点RBTNode<T>* search(T key);// (非递归实现)查找"红黑树"中键值为key的节点RBTNode<T>* iterativeSearch(T key);// 查找最小结点:返回最小结点的键值。T minimum();// 查找最大结点:返回最大结点的键值。T maximum();// 找结点(x)的后继结点。即,查找"红黑树中数据值大于该结点"的"最小结点"。RBTNode<T>* successor(RBTNode<T> *x);// 找结点(x)的前驱结点。即,查找"红黑树中数据值小于该结点"的"最大结点"。RBTNode<T>* predecessor(RBTNode<T> *x);// 将结点(key为节点键值)插入到红黑树中void insert(T key);// 删除结点(key为节点键值)void remove(T key);// 销毁红黑树void destroy();// 打印红黑树void print();
private:// 前序遍历"红黑树"void preOrder(RBTNode<T>* tree) const;// 中序遍历"红黑树"void inOrder(RBTNode<T>* tree) const;// 后序遍历"红黑树"void postOrder(RBTNode<T>* tree) const;// (递归实现)查找"红黑树x"中键值为key的节点RBTNode<T>* search(RBTNode<T>* x, T key) const;// (非递归实现)查找"红黑树x"中键值为key的节点RBTNode<T>* iterativeSearch(RBTNode<T>* x, T key) const;// 查找最小结点:返回tree为根结点的红黑树的最小结点。RBTNode<T>* minimum(RBTNode<T>* tree);// 查找最大结点:返回tree为根结点的红黑树的最大结点。RBTNode<T>* maximum(RBTNode<T>* tree);// 左旋void leftRotate(RBTNode<T>* &root, RBTNode<T>* x);// 右旋void rightRotate(RBTNode<T>* &root, RBTNode<T>* y);// 插入函数void insert(RBTNode<T>* &root, RBTNode<T>* node);// 插入修正函数void insertFixUp(RBTNode<T>* &root, RBTNode<T>* node);// 删除函数void remove(RBTNode<T>* &root, RBTNode<T> *node);// 删除修正函数void removeFixUp(RBTNode<T>* &root, RBTNode<T> *node, RBTNode<T> *parent);// 销毁红黑树void destroy(RBTNode<T>* &tree);// 打印红黑树void print(RBTNode<T>* tree, T key, int direction);
#define rb_parent(r) ((r)->parent)
#define rb_color(r) ((r)->color)
#define rb_is_red(r) ((r)->color==RED)
#define rb_is_black(r) ((r)->color==BLACK)
#define rb_set_black(r) do { (r)->color = BLACK;}while(0)
#define rb_set_red(r)  do { (r)->color = RED; } while (0)
#define rb_set_parent(r,p)  do { (r)->parent = (p); } while (0)
#define rb_set_color(r,c)  do { (r)->color = (c); } while (0)};

.cpp

#include "stdafx.h"
#include "MyRBTree.h"template<class T>
CMyRBTree<T>::CMyRBTree()
{
}template<class T>
CMyRBTree<T>::~CMyRBTree()
{
}/*
* 对红黑树的节点(x)进行左旋转
*
* 左旋示意图(对节点x进行左旋):
*      px                              px
*     /                               /
*    x                               y
*   /  \      --(左旋)-->           / \                #
*  lx   y                          x  ry
*     /   \                       /  \
*    ly   ry                     lx  ly
*
*
*/
template<class T>
void CMyRBTree<T>::leftRotate(RBTNode<T>*& root, RBTNode<T>* x)
{//定义一个指针y,指向x的右孩子;RBTNode<T> *y = x->right;//将"y的左孩子"设为"X的右孩子"x->right = y->left;if (y->left != nullptr){y->left->parent = x;}//将"X的父节点"设为"Y的父节点"y->parent = x->parent;if (x->parent == nullptr){root = y;}else{if (x->parent->left == x){x->parent->left = y;}else {x->parent->right = y;}}y->left = x;x->parent = y;}/*
* 对红黑树的节点(y)进行右旋转
*
* 右旋示意图(对节点y进行左旋):
*            py                               py
*           /                                /
*          y                                x
*         /  \      --(右旋)-->            /  \                     #
*        x   ry                           lx   y
*       / \                                   / \                   #
*      lx  rx                                rx  ry
*
*/
template<class T>
void CMyRBTree<T>::rightRotate(RBTNode<T>*& root, RBTNode<T>* y)
{//定义一个指针,指向Y的左孩子RBTNode *x = y->left;//1.X的右孩子设置为y的左孩子y->left = x->right;if (x->right != nullptr){x->right->parent = y;}//2.y的父亲节点设置为X的父亲节点x->parent = y->parent;if (y->parent == nullptr){root = x;}else {if (y->parent->left == y){y->parent->left = x;}else {y->parent->right = x;}}x->right = y;y->parent = x;
}

参考文献

https://www.cnblogs.com/skywang12345/archive/2004/01/13/3245399.html

面试题(32)|数据结构(11):红黑树相关推荐

  1. HashMap 数据结构之红黑树, 红黑树在什么时候左旋 右旋 如何旋转

    树结构是数据结构中最经典最常用的结构之一,也是面试中常问的面试题,最近学习了一下红黑树的知识,记录整理一下 文章目录 一.红黑树的特征 二.变色左旋和右旋 1.变色规则 2.左旋 3.右旋 总结 前言 ...

  2. 面试题:什么是红黑树【不看后悔一生】

    1.引入红黑树 今天在学习集合list.set和map的时候,发现set的一个实现类TreeSet和map的一个实现类TreeMap的底层数据结构都是红黑树,于是我仔细查阅了资料了解了什么是红黑树? ...

  3. 内核数据结构之红黑树

    红黑树是一种自平衡的二叉查找树,是Linux主要的二叉树结构.红黑树有一个特殊的颜色属性,要么红色,要么黑色.红黑树通过强制以下条件来保证红黑树仍然是半平衡的. 所有结点要是红色或黑色的. 叶子结点是 ...

  4. java treeset 红黑树_【数据结构】红黑树与跳表-(SortSet)-(TreeMap)-(TreeSet)

    SortSet 有序的Set,其实在Java中TreeSet是SortSet的唯一实现类,内部通过TreeMap实现的:而TreeMap是通过红黑树实现的:而在Redis中是通过跳表实现的: Skip ...

  5. 数据结构 — 浅析红黑树原理以及实现

    浅析红黑树原理以及实现 我们在上一篇博客认识到了平衡二叉树(AVLTree),了解到平衡二叉树的性质,其实平衡二叉树最大的作用就是查找,AVL树的查找.插入 和删除在平均 和 最坏情况下都是O(log ...

  6. 面试题:为什么用红黑树不用普通的AVL树

    在Jdk1.8版本后,Java对HashMap做了改进,在链表长度大于8的时候,将后面的数据由链表改为了存在红黑树中,以加快检索速度. 有疑问为什么是使用红黑树而不是AVL树,AVL树是完全平衡二叉树 ...

  7. 数据结构之红黑树(三)——删除操作

    删除一个节点相同有可能改变树的平衡性,并且,删除所造成的不平衡性比插入所造成的平衡性的修正更加复杂. 化繁为简是算法分析中一个经常使用的方法.以下我们将欲删除节点分为三大类:欲删除节点为叶子节点.欲删 ...

  8. JAVA数据结构之红-黑树

    本篇博客我会重点介绍对红-黑树的理解,重点介绍红-黑树的查找,这里我们将要讨论的算法称为自顶向下插入,也就是把沿着树向下查找插入点 Ⅰ.平衡树和非平衡树 平衡树和非平衡树:当插入一组数据关键字是按照升 ...

  9. 为什么java1.8 hashMap的数据结构是红黑树?

    众所周知,java1.7的时候hashMap结构还是[数组+链表],而在1.8版本结构变为了[数组+链表/红黑树],当链表长度达到8时,自动转换为红黑树结构. 那么为什么java1.8要对hashMa ...

  10. 【数据结构】红黑树前置知识——4阶B树

    学习目标: 学习4阶B树,使我们更好地理解为何红黑树进行平衡时的操作缘由,理清我们红黑树平衡时局部与整体的关系. 特别说明!!! 1 这里说的4阶B树是针对学习红黑树时对B树进行一定修改得到的4阶B树 ...

最新文章

  1. 2021年春季学期-信号与系统-第四次作业参考答案-MATLAB实验1
  2. 别再抱怨了,国内这么多优秀的Android资源你都知道吗?
  3. 线性规划、梯度下降、正规方程组——斯坦福ML公开课笔记1-2
  4. activemq控制发送频率_发送activemq
  5. 混合使用Objective-C,C++和Objective-C++
  6. java多线程之Semaphore信号量详解
  7. 推荐一个css帮助手册的版本 同时提供chm和在线
  8. Struts2表单验证的xml配置
  9. L1-049__056
  10. css实现椭圆绕圈动画
  11. Android 7.0 Settings Summary 小记
  12. unity text颜色渐变
  13. app如何助推用户从pc端转向手机端
  14. 当前数据中心运维管理工作中存在的问题
  15. Python中的对象实例化过程 用python解密__new__
  16. html语言下上标对齐,html常用标签基础
  17. Pycharm以及cmd调用Anaconda已配置环境的方法
  18. 加一度详解百度线索通,竞价新手必看福利!
  19. 精灵图和字体图标学习
  20. Android开发之App拍照系统相册展示

热门文章

  1. 霍夫直线检测代码实战
  2. php js实现登录注册,JavaScript实现登录注册验证
  3. 图像处理:黑白效果(灰度处理)
  4. python 直接退出程序_python 退出程序 Python程序运行后直接退出
  5. oracle 查询数据库中所有表名
  6. Ember Sword快来享受战斗吧
  7. 申请CloudFlare免费DNS服务
  8. Android5 喜刷刷
  9. Ubuntu14.04 安装VMware tools
  10. Java实现 foreach循环