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

湖南网站建设360o湖南竞价优化专业公司

湖南网站建设360o,湖南竞价优化专业公司,花都网站建设网页设计,wordpress文章下载美化框红黑树 红黑树的概念红黑树的性质红黑树结点的定义红黑树的插入红黑树的验证红黑树与AVL树的比较 红黑树的概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上…

红黑树

  • 红黑树的概念
  • 红黑树的性质
  • 红黑树结点的定义
  • 红黑树的插入
  • 红黑树的验证
  • 红黑树与AVL树的比较

红黑树的概念

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

红黑树的性质

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

为什么红黑树就能保证其最长路径中节点个数不会超过最短路径节点个数的两倍?

从性质3,4可以得出,一棵红黑树的最短可能路径就是全为黑结点,即为N:
在这里插入图片描述
而最长可能路径就是由一黑一红结点构成的路径,该路径当中黑色结点与红色结点的数目相同,即长度为2N ;
在这里插入图片描述

红黑树结点的定义

红黑树结点的定义其实和AVL树差不多,只不过红黑树结点少了平衡因子,多了颜色。

//枚举结点颜色
enum color
{RED,BLACK
};
template <class K, class V>
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){}
};

为什么构造结点时,默认将结点的颜色设置为红色?

我们可以发现,红黑树的有一条性质是所有路径黑色结点的数目都相等,如果欧姆尼新插入的结点默认为黑色,就会破坏这条性质,我们就需要对红黑树进行调整。

如果我们插入的是红结点,此时如果父结点是红结点,我们就需要进行调整,如果父结点是黑结点,我们就不需要进行调整。

红黑树的插入

红黑树的插入步骤分为以下三步:

  1. 根据二叉搜索树的性质,找到待插入位置;
  2. 在待插入位置插入新结点;
  3. 如果父结点为红色,就进行调整。

我们可以发现,前两步其实AVL树没有区别,我们只要在第三步进行调整就可以了。

那么,怎么对红黑树插入结点进行调整呢?

如果我们插入结点的父结点是黑色的,我们就不需要进行任何调整,因为这并没有破坏红黑树的性质;如果我们插入结点的父结点是红结点,我们就需要对红黑树进行调整了。

插入结点的父结点为红色,就说明祖父结点一定存在且为黑色,对红黑树的调整主要是对叔叔结点的调整。

红黑树的调整一共分为三种方式:

1.cur为红,p为红,g为黑,u存在且为红

在这里插入图片描述
插入结点为红,父结点为红,我们需要将父结点与叔叔结点都调整为黑色,然后将祖父结点调整为红色,如果此时g这棵树不为子树,就再将祖父结点调整为黑色;

对应的抽象图如下:
在这里插入图片描述
如果g不为子树,最后将g调整为黑色就完成了红黑树的调整;
在这里插入图片描述
如果g为子树,一次调整以后g还有双亲,双亲如果是红色,将p,u改为黑,g改为红,然后把g当成cur,继续向上调整,还要继续向上调整。

2.cur为红,p为红,g为黑,u不存在/u存在且为黑,p为g的左孩子,cur为p的左孩子或者p为g的右孩子,cur为g的右孩子

我们均已被插入结点在根结点左侧为例:

如果u节点不存在,则cur一定是新插入节点,因为如果cur不是新插入节点则cur和p一定有一个节点的颜色是黑色,就不满足性质:每条路径黑色节点个数相同。
在这里插入图片描述
此时我们只需要以p为旋转点进行右单旋,然后进行颜色调整即可:
在这里插入图片描述
当u存在且为黑时:

此时一定是情况一向上调整才会出现的情况,这种情况下cur不会是新插入的结点,是经过前一次调整以后的结点:
在这里插入图片描述
我们以新插入结点在a的左侧为例:
在这里插入图片描述

此时我们以g为旋转点进行右单旋,然后进行颜色调整,红黑树即可平衡;

同样,如果被插入结点在根结点右侧,我们只需要进行相应左旋在调整颜色即可实现红黑树平衡;

抽象图如下:

被插入结点在根结点左侧:
在这里插入图片描述
被插入结点在根结点右侧:
在这里插入图片描述

3.cur为红,p为红,g为黑,u不存在/u存在且为黑,p为g的左孩子,cur为p的右孩子或者p为g的右孩子,cur为p的左孩子

u不存在时:
在这里插入图片描述

当u存在且为黑时,我们以下面这种情况为例:
在这里插入图片描述
我们先已p为轴点进行左单旋,再以g为轴点进行右单旋,最后进行颜色调整,红黑树保持平衡;

抽象图如下:

被插入结点在根结点左侧:
在这里插入图片描述
被插入结点在根结点右侧:
在这里插入图片描述
代码实现:

bool Insert(const pair<K, V>& kv)
{//根结点为空if (_root == nullptr){//创建根结点_root = new Node(kv);//颜色变为黑_root->_col = BLACK;return true;}Node* cur = _root;Node* parent = nullptr;while (cur){//如果插入key值小于根结点key值if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}//如果插入key值大于根结点key值else if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}//相等,返回falseelse{return false;}}//创建cur结点cur = new Node(kv);//颜色初始化为红色cur->_col = RED;//如果插入key值小于parent结点key值if (parent->_kv.first > kv.first){//在左边插入parent->_left = cur;}//如果插入key值大于parent结点key值else{//在右边插入parent->_right = cur;}//跟父结点连接起来cur->_parent = parent;while (parent && parent->_col == RED){//定义祖父节点Node* grandfather = parent->_parent;assert(grandfather);assert(grandfather->_col == BLACK);//如果父结点在祖父节点左边if (parent == grandfather->_left){//定义叔叔结点在祖父结点右边Node* uncle = grandfather->_right;//情况一://叔叔结点存在且为红if (uncle && uncle->_col == RED){//进行颜色调整parent->_col = uncle->_col = BLACK;grandfather->_col = RED;//继续向上调整cur = grandfather;parent = cur->_parent;}//情况二和三://叔叔结点不存在或者存在且为黑else{//插入结点在父结点左边if (cur == parent->_left){//右单旋+颜色调整RotateR(grandfather);grandfather->_col = RED;parent->_col = BLACK;}//插入结点在父结点左边else{//左右双旋+颜色调整RotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}//如果父结点在祖父节点右边else{//定义叔叔结点在祖父结点左边Node* uncle = grandfather->_left;//情况一://叔叔结点存在且为红if (uncle && uncle->_col == RED){//颜色调整parent->_col = uncle->_col = BLACK;grandfather->_col = RED;//向上调整cur = grandfather;parent = cur->_parent;}//情况二和三://叔叔结点不存在或者存在且为黑else{//插入结点在父结点右边if (cur == parent->_right){//左单旋+颜色调整RotateL(grandfather);grandfather->_col = RED;parent->_col = BLACK;}//插入结点在父结点左边else{//右左双旋+颜色调整RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}//根结点变为黑色_root->_col = BLACK;return true;
}

红黑树的验证

我们可以判断每条路径的黑节点数量是否相等来判断该二叉树是否为红黑树:

void InOrder()
{_InOrder(_root);cout << endl;
}bool IsBalance()
{//如果根结点为空,返回true;if (_root == nullptr){return true;}//如果根结点为红色,则返回false;if (_root->_col == RED){cout << "根结点不是黑色" << endl;return false;}//定义一个黑色结点数量的基准值,为最左边路径黑色结点数量int benchmark = 0;Node* cur = _root;while (cur){if (cur->_col == BLACK){benchmark++;}cur = cur->_left;}//黑色结点数量int BlackNum = 0;return PrevCheck(_root, BlackNum, benchmark);
}
bool PrevCheck(Node* root, int BlackNum, int benchmark)
{//说明此时路径已经走完了if (root == nullptr){//如果基准值不等于黑色结点数量,返回falseif (benchmark != BlackNum){cout << " 某条黑色结点数量不相等" << endl;return false;}//否则返回truereturn true;}//根结点为黑色,黑色结点数量++if (root->_col == BLACK){BlackNum++;}//存在连续红色节点,返回falseif (root->_col == RED && root->_parent->_col == RED){cout << "存在连续的红色结点" << endl;return false;}//递归进行判断return PrevCheck(root->_left, BlackNum, benchmark)&& PrevCheck(root->_right, BlackNum, benchmark);
}

红黑树与AVL树的比较

红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O(log N),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单。

http://www.ds6.com.cn/news/4615.html

相关文章:

  • 大型网站seo方法如何做自己的网站
  • 网站中的公司地址怎么做20个排版漂亮的网页设计
  • 嘉定网站设计友情链接怎么购买
  • 国内网站备案要多久网站一般需要怎么推广
  • 网络营销推广外包服务网络seo是什么工作
  • 网站制作培训多少钱seo的中文名是什么
  • 镇江网站设计制作国内新闻最新消息十条
  • 网络团队深圳seo顾问
  • 磐安做网站关键词搜索爱站网
  • 贵州萝岗seo整站优化搜索引擎推广
  • wordpress传上去北京网站优化效果
  • 网站建设方案预算费用预算手机优化大师官方版
  • 学计算机网站建设做互联网项目怎么推广
  • Excel怎么做网站链接今日最新新闻重大事件
  • 福建网站建设公化工seo顾问
  • 增城住房和城乡建设局网站nba篮网最新消息
  • 阿里云域名怎么做网站win10系统优化软件
  • 做网站流量是什么刚刚地震最新消息今天
  • 做网站以前出名的公司市场调研一般怎么做
  • php企业网站建设论文媒体资源网官网
  • 北京网站建设与维护网络营销策划方案模板范文
  • 鄂州网站制作人才招聘百度网盘下载
  • 电子商务平台网站模板上海有实力的seo推广咨询
  • 专做情侣装网站百度网盘云资源搜索引擎
  • 网站备案 做网站时就需要吗b2b推广网站
  • 公司做网站需要服务器吗重庆seo网络营销
  • 网站建设与管理 管理课程百度经验手机版官网
  • 网站建设系统优势玉林seo
  • 公司转让一般在什么网汕头seo按天付费
  • 可以安装两个wordpress重庆百度seo排名