【数据结构】简单介绍红黑树

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

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

满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍

定义结点
enum COLOR {
	RED, BLACK
};

template <class T>
struct RBTreeNode {
	RBTreeNode<T>* _pLeft;
	RBTreeNode<T>* _pRight;
	RBTreeNode<T>* _pParent;
	T _data;
	int _color;
	//默认给成红色,红色只有一种情况会破坏性质限制
	RBTreeNode(const T& data = T(), COLOR color = RED) 
		: _pLeft(nullptr)
		, _pRight(nullptr)
		, _pParent(nullptr)
		, _data(data)
		, _color(color) {}
};
红黑树结构

在这里插入图片描述

template <class T>
class RBTree {
public:
	typedef RBTreeNode<T> Node;

	RBTree() {
		_pHead = new Node();
		_pHead->_pParent = nullptr;
		_pHead->_pLeft = _pHead;
		_pHead->_pRight = _pHead;
	}
	其他接口
private:
	Node* _pHead;
}:

红黑树的插入操作

红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:

  1. 按照二叉搜索的树规则插入新节点
//按照二叉搜索树的规则找待插结点在红黑树中的位置
Node* pCur = pRoot;
Node* pParent = nullptr;
while (pCur) {
	pParent = pCur;
	if (data < pCur->_data)
		pCur = pCur->_pLeft;
	else if (data > pCur->_data)
		pCur = pCur->_pRight;
	else
		return false;
}

//插入新节点
pCur = new Node(data);
if (data < pParent->_data)
	pParent->_pLeft = pCur;
else
	pParent->_pRight = pCur;
pCur->_pParent = pParent;
  1. 检测新节点插入后,红黑树的性质是否造到破坏

因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何性质,则不需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连在一起的红色节点,此时需要对红黑树分情况来讨论:

  • 情况一: cur为红,p为红,g为黑,u存在且为红
    在这里插入图片描述
  • 情况二: cur为红,p为红,g为黑,u不存在/u为黑
    在这里插入图片描述
  • 情况三: cur为红,p为红,g为黑,u不存在/u为黑
    在这里插入图片描述
while (pParent != _pHead && RED == pParent->_color) {
	Node* grandFather = pParent->_pParent;
	//父亲结点在祖先结点的左子树
	if (pParent == grandFather->_pLeft) {
		Node* uncle = grandFather->_pRight;
		//情况1:叔叔结点存在且为红
		if (uncle && uncle->_color == RED) {
			pParent->_color = BLACK;
			uncle->_color = BLACK;
			grandFather->_color = RED;
			pCur = grandFather;
			pParent = pCur->_pParent;
		}
		else {	//叔叔结点不存在 || 叔叔结点存在&&黑色
		 //情况三:变为情况二
			if (pCur == pParent->_pRight) {
				RotateL(pParent);
				swap(pParent, pCur);
			}
			//情况二:
			pParent->_color = BLACK;
			grandFather->_color = RED;
			RotateR(grandFather);
		}
	}

	//父亲结点在祖先结点的右子树
	else {
		Node* uncle = grandFather->_pLeft;
		if (uncle && uncle->_color == RED) {
			pParent->_color = BLACK;
			uncle->_color = BLACK;
			grandFather->_color = RED;
			pCur = grandFather;
			pParent = pCur->_pParent;
		}
		else { //情况二和情况三
		 	//情况三
			if (pCur == pParent->_pLeft) {
				RotateR(pParent);
				swap(pParent, pCur);
			}
			//情况二
			pParent->_color = BLACK;
			grandFather->_color = RED;
			RotateL(grandFather);
		}
	}
}
//可能把根结点改成红的了
pRoot->_color = BLACK;
_pHead->_pLeft = LeftMost();
_pHead->_pRight = RightMost();
return true;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值