当前位置: 首页 > news >正文

C++进阶——红黑树

C++进阶——红黑树

概念

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过
对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩
倍,因而是接近平衡的。

在这里插入图片描述

红黑树的性质

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的两个孩子结点是黑色的(俩个红不能相邻
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
  5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

其实可以总结一下:最短的树枝一定是全黑的,最长的一定是红黑交替的,按照每个树枝黑节点都相同则全黑的一定是红黑相间的二倍。

实现红黑树

定义一个节点

enum color//定义颜色
{RED,BLACK
};
template<class K,class T>struct RBTreeNode{RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;pair<K, V> _kv;color _col;RBTreeNode(const pair(K, V)& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _col(RED){}};

思考:在节点的定义中,为什么要将节点的默认颜色给成红色的?
因为刚刚说的性质中第三条比第四条更好维护。

红黑树结构

为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为跟节点必须为黑色,为了与根节点进
行区分,将头结点给成黑色,并且让头结点的 pParent 域指向红黑树的根节点,pLeft域指向红黑树中最小的
节点,_pRight域指向红黑树中最大的节点,如下:
在这里插入图片描述

查找

其实结合普通二叉树一样就不多展开讲解了。

	node* Find(const K& key){node* cur = _root;while (cur){if (cur->_kv > key){cur = cur->_left;}else if (cur->_kv < key){cur = cur->_right;}else{return cur;}}return nullptr;}

插入

前期插入也很简单,但是变色还有要控制变色之后整棵树的性质不变要做出——旋转
约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点。a、b、c、d、e都是高度不一定的子树(只要满足性质可以为空)。
情况一: cur为红,p为红,g为黑,u存在且为红
在这里插入图片描述
变色后:
在这里插入图片描述

然后grandfather变成心得cur继续向上变色,直到g是根节点变成黑色,如果不是根节点就还是变成红色,并继续向上调整。
解决方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。

情况二: cur为红,p为红,g为黑,u不存在/u为黑
是一条线方向
右旋:
在这里插入图片描述
左旋:
在这里插入图片描述

在这里插入图片描述

p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,
p为g的右孩子,cur为p的右孩子,则进行左单旋转
p、g变色–p变黑,g变红

情况三: cur为红,p为红,g为黑,u不存在/u为黑
但是是折线方向
在这里插入图片描述

bool Insert(const pair<K,V>& kv){//先进行连接if (_root == nullptr){_root = new node(kv);_root->_col = BLACK;return true;}node* parent = nullptr;node* cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else{return false;}}cur = new node(kv);if (parent->_kv.first > kv.first){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;//接下来要开始变色了。while (parent && parent->_col == RED){node* grandfather = parent->_parent;if (grandfather->_left == parent){node* uncle = grandfather->_right;//情况1:u存在且为红,变色处理,并继续往上处理if (uncle && uncle->_col == RED){parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;// 继续往上调整cur = grandfather;parent = cur->_parent;}else//情况2+3:u不存在/u尊在且为黑——旋转加变色{//     g//   p   u// c if (cur == parent->_left){RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{//     g//   p   u//     cRotateL(parent);RotateR(grandfather);cur->_col = BLACK;//parent->_col = RED;grandfather->_col = RED;}break;}}else//g->right=p{node* uncle = grandfather->_left;// 情况1:u存在且为红,变色处理,并继续往上处理if (uncle&& uncle->_col == RED){parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;// 继续往上调整cur = grandfather;parent = cur->_parent;}else//情况2+3:u不存在/u存在且为黑,旋转+变色{//     g//  u     p//          cif (cur == parent->_right){RotateL(grandfather);grandfather->_col = RED;parent->_col = BLACK;}else{//     g// u     p//      cRotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->col=BLACK;//根永远是黑色的。return true;}

检测

bool isBalance(){if (_root && _root->_col == RED){cout << "根节点颜色是红色" << endl;return false;}int benchmark = 0;node* cur = _root;while (cur){if (cur->_col == BLACK)++benchmark;cur = cur->_left;}// 连续红色节点return _Check(_root, 0, benchmark);}
bool _Check(node* root, int blackNum, int benchmark){if (root == nullptr){if (benchmark != blackNum){cout << "某条路径黑色节点的数量不相等" << endl;return false;}return true;}if (root->_col == BLACK){++blackNum;}if (root->_col == RED&& root->_parent&& root->_parent->_col == RED){cout << "存在连续的红色节点" << endl;return false;}return _Check(root->_left, blackNum, benchmark)&& _Check(root->_right, blackNum, benchmark);}int _Height(node* root){if (root == NULL)return 0;int leftH = _Height(root->_left);int rightH = _Height(root->_right);return leftH > rightH ? leftH + 1 : rightH + 1;}void _InOrder(node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << " ";_InOrder(root->_right);}

用以上程序可以测出是否是红黑平衡树。

测试结果

void Test_RBTree1()
{//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14, 16, 3, 7, 11, 9, 26, 18, 14, 15 };RBTree<int, int> t1;for (auto e : a){/*	if (e == 14){int x = 0;}*/t1.Insert(make_pair(e, e));//cout << e << "插入:" << t1.IsBalance() << endl;}t1.InOrder();cout << t1.IsBalance() << endl;
}void Test_RBTree2()
{srand(time(0));const size_t N = 5000000;RBTree<int, int> t;for (size_t i = 0; i < N; ++i){size_t x = rand()+i;t.Insert(make_pair(x, x));//cout << t.IsBalance() << endl;}//t.Inorder();cout << t.IsBalance() << endl;cout << t.Height() << endl;
}

在这里插入图片描述

在这里插入图片描述

http://www.lryc.cn/news/69089.html

相关文章:

  • 什么是NTFS for Mac?2023新版本如何下载
  • Python泰裤辣丨520写一个自动换壁纸软件,将女友照骗放进去送给她
  • CMake: 设置编译选项
  • 美团Java开发一面凉经
  • Java面试知识点(全)-spring面试知识点二
  • 【音视频开发】基础知识:视频封装格式和编码格式
  • OData Web API 一个开放标准的协议
  • PT100温度采集
  • ThinkSystem DM 全闪存阵列 —— 通过全闪存 NVMe 转型加速您的业务
  • SpringCloud------代码demo(二)
  • TCL语法
  • Partial convolution Gated convolution
  • 量化投资 无套利 No-arbitrage
  • 小程序容器助力智能移动门户统一
  • opencv-python相机标定详解
  • 由斯坦福、Nautilus Chain等联合主办的 Hackathon 活动,现已接受报名
  • PBDB Data Service:Measurements of specimens(标本测量)
  • 低调的接口工具 ApiKit
  • opengauss 的回归测试
  • 计算机组成原理基础练习题第四章-计算机的运算方法
  • SpringBoot定时任务里的多线程
  • YOLO V3 SPP ultralytics 第二节:根据yolo的数据集,生成准备文件和yolo的配置文件
  • camunda流程引擎connector如何使用
  • ECO基本概念:pre-mask eco gen patch flow
  • 【初学人工智能原理】【4】梯度下降和反向传播:能改(下)
  • 微信小程序路由传参
  • 深入篇【C++】类与对象:再谈构造函数之初始化列表与explicit关键字
  • 广东棒球发展建设·棒球1号位
  • 浅谈PMO对组织战略的支持︱美团骑行事业部项目管理中心负责人边国华
  • 互联网医院资质代办|互联网医院牌照的申请流程