[共同学习] 红黑树浅见

红黑树的概念

自平衡二叉查找树,一种特化的AVL树,在每个结点增加一个存储位表示结点颜色(不是 red 就是 black ),通过任何一条从根到叶子的路径上各个结点着色方式的限制,确保没有一条路径会比其他路径长出两倍,因而是接近平衡
在这里插入图片描述

红黑树的性质

或是一棵空树,或是具有以下性质的二叉搜索树:

  1. 每个结点不是红色就是黑色;
  2. 根结点是黑色;
  3. 如果一个结点是红色,那它的孩子结点是黑色–没有连续的红色结点
  4. 叶子结点(指NIL空结点)是黑色;
  5. 从任意一个结点到其所有后代叶结点的简单路径上均包含数目相同的黑色结点

红黑树的性质保证了最长路径中结点的个数一定不会超过最短路径中结点个数的二倍


红黑树的结构

结点的定义

enum COLOR{RED,BLACK};  //结点的颜色

//红黑树结点的定义
template<class K, class V>
struct RBTreeNode{
	RBTreeNode(const pair<K, V>& kv = pair<K,V>(),Color color = RED)
		:_left(nullptr),_right(nullptr),_parent(nullptr)
		,_valtype(kv),_color(color)
	{}

	RBTreeNode<K, V>* _left;  //结点的左孩子
	RBTreeNode<K, V>* _right;  //结点的右孩子
	RBTreeNode<K, V>* _parent;  //结点的双亲-方便红黑树实现旋转
	pair<K, V> _valtype;
	COLOR _color;  //结点颜色
};

结点默认是红色,插入时可能会违背性质3:没有连续的红色结点;
但结点默认是黑色,插入时必然会违背性质5:任意结点到其叶子节点的路径上黑色结点个数相同


头结点的加入

为了实现关联式容器简单,给红黑树增加一个头结点,为了和根结点进行区分,将头结点着色为红色。头结点的 _parent 指向根结点,_left 指向红黑树中最小结点,_right 指向红黑树中最大结点。
在这里插入图片描述
写在构造函数里

RBTree():_head(new Node){
	_head->_left = _head->_right = _head;
}

插入操作

1.按照二叉树的规则插入新结点

if (_head->_parent == nullptr){  //只有头结点 -> 空树
	Node* root = new Node(kv);  //创建根结点
	_head->_parent = root;
	_head->_left = _head->_right = root;
	root->_parent = _head;
	root->_color = BLACK;  //根结点为黑色
	return true;
}

//树不为空,寻找插入的位置,同二叉搜索树的插入
Node* cur = _head;
Node* parent = nullptr;
while (cur){
	parent = cur;
	//valtype为<K, V>键值对类型,比较键值K,不允许重复
	if (cur->_valtype.first == kv.first)
		return false;
	else if (cur->_valtype.first > kv.first)
		cur = cur->_left;
	else
		cur = cur->_right;
}
cur = new Node(kv);
if (parent->_valtype.first > kv.first)
	parent->_left = cur;
else
	parent->_right = cur;
cur->_parent = parent;

2.检测红黑树的性质是否被破坏,进行调整
新结点默认是红色,如果其双亲结点是黑色则不需要调整;如果其双亲结点也是红色,需要进行以下讨论
约定:cur为当前节点,p为父结点,g为祖先结点,u为叔叔结点

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

在这里插入图片描述
调整策略
如果a,b,c,d,e是空树:
  (1)如果g是根结点,将p,u染成黑色
在这里插入图片描述
  (2)如果g不是根结点,g的双亲为黑色,p,u染成黑色(导致该路径黑色结点个数+1),g染成红色
在这里插入图片描述
  (3)如果g不是根结点,g的双亲为红色,p,u染成黑色,g染成红色,把g继续向上调整
在这里插入图片描述
如果a,b,c,d,e不是空树:新插入结点只会是叶子结点,a,b非空树可以理解为插入结点调整后出现cur和p同时是红色,与上面(3)相同,需要继续向上调整

情况2:p为红,g为黑,u不存在或u为黑

u不存在
在这里插入图片描述
cur一定是新插入结点,且a,b,c为空树,因为:cur插入前该树要满足红黑树的性质-不能有连续红色结点,任意结点每条路径黑色结点个数相等==(g的右孩子路径黑色结点个数为1,所以g-p-cur-a路径黑色结点个数也只能为1)==
u为黑色
在这里插入图片描述
cur不是新插入结点,且之前一定是黑色,现在被调整为红色(理由同上)
调整策略

  交换p和g的颜色

  p为g的左孩子,cur为p的左孩子:以g为根进行右单旋
在这里插入图片描述

  p为g的右孩子,cur为p的右孩子:以g为根进行左单旋(同上)

情况3:p为红,g为黑,u不存在或u为黑

与情况2相同,但是:
  p是g的左子树,cur是p的右子树:以p为根进行左单旋,红黑树变为情况2中的场景,按照情况2解决
在这里插入图片描述
  p是g的右子树,cur是p的左子树:以p为根进行右单旋,红黑树依旧变为情况2中的场景,按照情况2解决

调整完更新指针指向


红黑树的检测

空树,或者:
根是黑色,任意结点到叶子结点的简单路径黑色结点树相同,没有连续的红色结点。

与AVL树的比较

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


没有红黑树代码

撕不动,告辞!
在这里插入图片描述


–以上–

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值