红黑树是一棵二叉搜索树;树种每一个节点的颜色不是黑色就是红色。本篇中只实现用节点的颜色来描述红黑树,性质如下:

RB1:根节点和所有外部节点都是黑色;

RB2:在根至外部节点路径上,没有连续两个节点是红色;

RB3:在所有根至外部节点的路径上,黑色节点的数目都相同;

实现红黑树,首先需要定义树节点,节点包括:

1:节点颜色,黑色或者白色,用整型或者布尔类型表示,也可以预设两个宏;

2:节点权值,用来保存节点的数据;

3:左右子树指针;

首先是红黑树的定义,本例中红黑树继承自BST(二叉搜索树),即:

#define BLACK 1
#define RED 0template<class T>
class RBTree : public binarySearchTree<T, int>
{
public:RBTree() : binarySearchTree() {}~RBTree() {}void insert(const T& key) {insert(root, key);}void remove(const T& key) {remove(root, key);}private:binaryTreeNode<pair<const T, int>>*insert(binaryTreeNode<pair<const T, int>>*&, const T&);binaryTreeNode<pair<const T, int>>*remove(binaryTreeNode<pair<const T, int>>*&, const T&);binaryTreeNode<pair<const T, int>>*maximun(binaryTreeNode<pair<const T, int>>*);binaryTreeNode<pair<const T, int>>*minimun(binaryTreeNode<pair<const T, int>>*);int color(binaryTreeNode<pair<const T, int>>*);}

和AVL树类似,插入删除操作也是利用递归实现,所以在私有成员中存在实现递归调用的重载函数。

模板参数T为节点权值的类型,int为颜色类型。

insert插入函数:在以该节点为根节点的子树中插入新权值,返回插入后该子树的根节点。

remove删除操作:在以该节点为根节点的子树中删除特定权值的节点,返回删除后子树的根节点。

maximun函数:返回以该节点为根节点的子树中权值最大的节点。

minimun函数:返回以该节点为根节点的子树中权值最小的节点。

color函数:返回函数的颜色。

template<class T>
int RBTree<T>::color(binaryTreeNode<pair<const T,int>>* pnode)
{if(pnode == NULL)return BLACK;return pnode->element.second;
}

插入操作步骤如下:
步骤1:找到待插入的位置,即逐个比较权值,若该节点权值小于待插入权值,则在右子树中插入;若该节点权值大于待插入权值,则在左子树中插入。

步骤2:申请新节点,若树为空,则新节点为黑色;若树非空,则新节点为红色。

步骤3:改变相关节点的颜色,调整树平衡。

申请新节点的代码如下:

template<class T>
binaryTreeNode<pair<const T, int>>*
RBTree<T>::insert(binaryTreeNode<pair<const T, int>>* &pnode, const T& key)
{if(pnode == NULL){if(root == NULL)pnode = new binaryTreeNode<pair<const T, int>>*(pair<const T, int>(key, BLACK));elsepnode = new binaryTreeNode<pair<const T, int>>*(pair<const T, int>(key, RED)); }/*...*/
}

接下来就是执行比较插入的过程,涉及到对节点颜色进行修改的内容,我们先了解一下需要哪些调整。

插入操作的树平衡被破坏无非是存在两个连续的红色节点,违反了RB2。

同时,若违反RB2,则新插入节点和其父节点都应为红色,那么祖父节点必须为黑色(因为插入之前是平衡的)。

被破坏的情况有以下几种,假设子树的根节点为pnode,插入的节点为ptNode:

第一种情况:pnode的左孩子和右孩子都为红色,新节点是pnode孩子的孩子。

插入节点为pnode->leftChild->leftChild或pnode->leftChild->rightChild
color(pnode->leftChild) == RED && color(pnode->rightChild) == RED  
                              或者                 

插入节点为pnode->rightChild->leftChild或pnode->rightChild->rightChild
color(pnode->rightChild) == RED && color(pnode->leftChild) == RED    

解决方案:

1:将根节点的左右子树的颜色涂上黑色;

2:若pnode不是整个红黑树的根节点,则将pnode涂上红色

3:返回pnode;

代码实现:

template<class T>
binaryTreeNode<pair<const T,int>>*
RBTree<T>::rModify(binaryTreeNode<pair<const T, int>>* pnode)
{pnode->leftChild->element.second = BLACK;pnode->rightChild->element.second = BLACK;if(pnode != root)pnode->element.second = RED;return pnode;
}

第二种情况:pnode的左孩子为红色,右孩子为黑色(也可以是外部节点),新节点是pnode左孩子的孩子。

插入节点为pnode->leftChild->leftChild或pnode->leftChild->rightChild
color(pnode->leftChild) == RED && color(pnode->rightChild) == BLACK                       

解决方案:

1:若插入的是pnode左孩子的左孩子,则进行右旋操作;若插入的是pnode左孩子的右孩子,则进行先左旋后右旋操作;此时pnode为新根节点。

2:将新的根节点涂黑,将新根节点右孩子涂红。

3:返回根节点。

代码实现:

template<class T>
binaryTreeNode<pair<const T,int>>*
RBTree<T>::LbModify(binaryTreeNode<pair<const T, int>>* pnode)
{pnode->element.second = BLACK;pnode->rightChild->element.second = RED;return pnode;
}

函数调用:

if(color(pnode->rightChild) == BLACK && color(pnode->leftChild) == RED)
{if(key > pnode->leftChild->element.first)pnode = leftRightRotation(pnode);elsepnode = rightRotation(pnode);pnode = LbModify(pnode);
}

第三种情况:pnode的右孩子为红色,左孩子为黑色,新节点为pnode右孩子的孩子。

插入节点为pnode->rightChild->leftChild或pnode->rightChild->rightChild
color(pnode->rightChild) == RED && color(pnode->leftChild) == BLACK  

解决方案:

1:若新节点是pnode右孩子的右孩子,进行左旋操作;若新节点是pnode右孩子的左孩子,进行先右旋后左旋操作,此时pnode为新的根节点。

2:将新的根节点涂黑,新根节点的左孩子涂红。

3:返回新根节点。

代码实现:

template<class T>
binaryTreeNode<pair<const T,int>>*
RBTree<T>::RbModify(binaryTreeNode<pair<const T, int>>* pnode)
{pnode->element.second = BLACK;pnode->leftChild->element.second = RED;return pnode;
}

调用代码:

if(color(pnode->leftChild) == BLACK && color(pnode->rightChild) == RED)
{if(key > pnode->rightChild->element.first)pnode = leftRotation(pnode);elsepnode = rightLeftRotation(pnode);pnode = RbModify(pnode);
}

插入函数代码:

template<class T>
binaryTreeNode<pair<const T, int>>*
RBTree<T>::insert(binaryTreeNode<pair<const T, int>>* &pnode, const T& key)
{if(pnode == NULL)    //申请新节点,空则为黑色,非空则为红色。{if(root == NULL)pnode = new binaryTreeNode<pair<const T, int>>*(pair<const T, int>(key, BLACK));elsepnode = new binaryTreeNode<pair<const T, int>>*(pair<const T, int>(key, RED));  }else{if(key < pnode->element.first){//如果key小,则在左子树中插入pnode->leftChild = insert(pnode->leftChild, key);//左子树中插入后,若左孩子的孩子是红色,则需要进一步判断。if(pnode->leftChild->leftChild != NULL && color(pnode->leftChild->leftChild) == RED)||(pnode->leftChild->rightChild != NULL && color(pnode->leftChild->rightChild) == RED){//若左孩子是红色,则需要调整if(color(pnode->leftChild) == RED){if(color(pnode->rightChild) == RED)  //若右孩子是黑色,为第一种情况pnode = rModify(pnode);else             //否则,为第二种或者第三种{if(key > pnode->leftChild->element.first)pnode = leftRightRotation(pnode);elsepnode = rightRotation(pnode);pnode = LbModify(pnode);}}}}//与上述对称else if(key > pnode->element.first){pnode->rightChild = insert(pnode->rightChild, key);if(pnode->rightChild->leftChild != NULL && color(pnode->rightChild->leftChild) == RED) ||(pnode->rightChild->rightChild != NULL && color(pnode->rightChild->rightChild) == RED){if(color(pnode->rightChild) == RED){if(color(pnode->leftChild) == RED)pnode = rModify(pnode);else{if(key > pnode->rightChild->element.first)pnode = leftRotation(pnode);elsepnode = rightLeftRotation(pnode);pnode = RbModify(pnode);}}}}}return pnode;
}

数据结构-----红黑树的插入操作相关推荐

  1. Python实现红黑树的插入操作

    Python实现红黑树的插入操作 本专栏中的上一篇文章介绍了什么是红黑树,以及红黑树的旋转和变色. 参考:https://blog.csdn.net/weixin_43790276/article/d ...

  2. 彻底理解面试难点之rb-tree(红黑树)续--对红黑树的插入和删除操作的一些理解!!!

    这里主要讲一下对红黑树的插入和删除操作的一些理解 对于红黑树的一些相关性质的介绍,上篇已经讲了,这里不再介绍,有需要了解的,可以翻前面的博客看看. 1.红黑树的插入操作 对于红黑树的元素插入,我们首先 ...

  3. 红黑树检索/插入/删除

    正文 红黑树也是二叉查找树,我们知道,二叉查找树这一数据结构并不难,而红黑树之所以难是难在它是自平衡的二叉查找树,在进行插入和删除等可能会破坏树的平衡的操作时,需要重新自处理达到平衡状态.现在在脑海想 ...

  4. 红黑树的删除_Python实现红黑树的删除操作

    上一篇文章使用Python实现了红黑树的插入操作.参考:Python实现红黑树的插入操作本篇文章使用Python实现红黑树的删除操作.先将红黑树的5条特性列出来:1. 节点是红色或黑色.2. 根节点是 ...

  5. Python实现红黑树的删除操作

    Python实现红黑树的删除操作 本专栏的上一篇文章使用Python实现了红黑树的插入操作.参考:https://blog.csdn.net/weixin_43790276/article/detai ...

  6. 数据结构---红黑树的原理

    产生原因 有了AVL树为啥需要红黑树呢,我们知道AVL树可以保证查询的时间复杂度为O(long 2^N),但是我们知道AVL树的插入操作,结点之间调整非常复杂,导致AVL树的性能非常低下. 红黑树,是 ...

  7. C++数据结构 —— 红黑树

    目录 1.红黑树概念 2.红黑树节点的定义 3.红黑树的插入操作 4.红黑树的调整动作 4.1调整动作1 4.2调整动作2 4.3调整动作3 4.4插入算法的完整代码 4.5验证红黑树 4.6完整代码 ...

  8. 数据结构-红黑树插入结点示例

    数据结构-红黑树插入结点示例 1.红黑树简介 2.在线可视化生成红黑树工具 3.红黑树插入结点性质和规则 3.1.红黑树插入结点性质 3.2.红黑树插入结点规则 4.红黑树插入结点示例 4.1.红黑树 ...

  9. 红黑树及其插入、删除操作

    在二叉搜索树中,基本操作如结点的插入.删除.查找的性能上界都得不到保证,原因在于二叉搜索树的构造依赖于其结点值的插入顺序,最坏情况下二叉搜索树会退化为单链表(如下图所示).因此我们需要对二叉搜索树做出 ...

最新文章

  1. 坚持写博客给我带来了什么
  2. HDUOJ-----2175取(m堆)石子游戏
  3. python简介怎么写-python怎么写函数
  4. 计算时间差的Oracle函数
  5. Sqlserver2014下载与安装
  6. SpringBoot+Vue表单文件上传
  7. Use JPA API
  8. GRAPH ATTENTION NETWORKS 学习翻译
  9. mysql数据恢复或数据找回方法
  10. postgis 栅格数据_postGIS教程
  11. css 屏幕背景图片 img.html
  12. 卡车自动装载系统(ATLS)的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  13. 关于result = unpickler.load()ModuleNotFoundError: No module named ‘models‘解决
  14. 【warm up】热身训练 的学习率设置
  15. 【Python_PyQtGraph 学习笔记(四)】基于PyQtGraph设置槽函数,实现保存图片到本地的功能
  16. python将汉字转为拼音字母_科学网—[转载]python中文汉字转拼音 - 陈明杰的博文...
  17. idea社区版配置jsp
  18. 音视频学习之ffmpeg时间戳相关整理(时间基tbr,tbn,tbc)
  19. scala akka 修炼之路6(scala函数式柯里化风格应用场景分析)
  20. 纯前端实现下载xlsx.js实现下载

热门文章

  1. Dockerfile构建nginx镜像
  2. openwrt如何单独编译uboot
  3. 牛客网测试题--小a和黄金街道
  4. 航旅事业群面试(li)
  5. 无法删除DLL文件解决方法(转)
  6. SharePoint 2010 在多台前端环境 还原 网站集 问题解析
  7. 【数据结构与算法】之深入解析“打家劫舍II”的求解思路与算法示例
  8. 程序员之提升开发效率非常实用的十个工具网站分享
  9. OpenGL ES之深入解析如何实现“手写绘画板”
  10. 10.2.4 练习题