一直觉得数据结构中最难以搞懂的结构之一就是红黑树了。所以一开始就对红黑树有一股“敬畏感”,所以在学习红黑树的时候在网上查找了很多资料。但是网上的资料在讲解时条理不清,有的只是点甚至一笔带过,树的变化也没有体现出来。自己总结了好久才把它给搞定,再此,向大家分享一下个人的思路。
首先,我们要知道红黑树的规则:
性质1. 节点是红色或黑色。
性质2. 根是黑色。
性质3. 所有叶子都是黑色(叶子是NIL节点)。
性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有简单路径 都包含相同数目的黑色节点。
咋一看红黑树的规则很多,要想所有节点都满足这5条性质还是有难度的,但是其实这5条性质是相互依赖的,只要我们掌握一些方法去调整子树,整棵树将会满足这些性质(在这里不得不感叹前辈们的智慧真的是相当的牛)。
在这里博主主要讨论的是红黑树的插入操作:
红黑树的插入节点是不难的,它的插入操作类似于二叉搜索树,在这里就略过了,但是有一点要说明,每个新插入的结点默认都是红色的,所以只要心插入的结点的父节点是黑色,那么我们就无需调整树结构,红黑树并不是AVL平衡二叉树那么的严格。这也是红黑树应用广泛的原因。
总结起来新插入节点可以分为以下几种情况:(cur为新插入的结点,root为根节点,parent为cur的父节点,uncle为parent的兄弟结点,grandpa为parent的父节点)
1.root为空
将新结点给root,并将结点改为黑色(性质2)。
2.parent的颜色为黑色
直接插入cur(直接就满足所有条件)
3.parent的颜色为红色
此情况下有可以分为以下几种情况:
1.cur为红,parent为红,grandpa为黑,uncle存在且为红
调整颜色:grandpa为红,uncle为黑,parent为黑(注意不管是何种情况,cur的颜色一致不变,为红)
2.cur为红,parent为红,grandpa为黑,uncle不存在或者为黑调整树和结点颜色:(一)grandpa->left==parent parent->left==cur。
右旋转,parent为黑,grandpa为红,cur为红
(二)grandpa->right==parent parent->right=cur。
左旋转,parent为黑,grandpa为红
(三)grandpa->_left == parent,parent->_right == cur
左右双旋,cur为黑,grandpa为红
(四)grandpa->right == parent,parent->left == cur
右左双旋,cur为黑,grandpa为红
<span style="font-size:14px;">#pragma once
#include<iostream>
using namespace std;
enum Color
{
RED,
BLACK
};
template<class K,class V>
struct RBNode
{
RBNode<K, V>* _left;
RBNode<K, V>* _right;
RBNode<K, V>* _parent;
K _key;
V _value;
Color _color;
RBNode(const K& key, const V& value)
:_left(NULL)
, _right(NULL)
, _parent(NULL)
, _key(key)
, _value(value)
, _color(RED)
{}
};
template<class K,class V>
class RBTree
{
public:
typedef RBNode<K, V> Node;
RBTree()
:_root(NULL)
{}
bool Insert(const K& key, const V& value)
{
if (_root == NULL)
{
_root = new Node(key, value);
_root->_color = BLACK;
return true;
}
Node* cur = _root;
Node* parent = NULL;
while (cur)
{
parent = cur;
if (cur->_key > key)
cur = cur->_left;
else if (cur->_key < key)
cur = cur->_right;
else
return false;
}
cur = new Node(key, value);
cur->_parent = parent;
if (parent->_key > key)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
if (parent->_color == BLACK)//如果插入的结点的父节点是黑色,那么不必调整
return true;
while (cur != _root &&cur->_color == RED&& parent->_color == RED)//只有当parent为红,cur为红时调整,cur!=root保证parent不为空
{
Node* grandpa = parent->_parent;
Node* uncle = NULL;
if (parent == grandpa->_left)
uncle = grandpa->_right;
else
uncle = grandpa->_left;
if (uncle&&uncle->_color == RED)
{
grandpa->_color = RED;
uncle->_color = BLACK;
parent->_color = BLACK;
}
else
{
if (grandpa->_left == parent&&parent->_left == cur)
{
_RotateR(grandpa);
grandpa->_color = RED;
parent->_color = BLACK;
cur->_color = RED;
}
if (grandpa->_right == parent&&parent->_right == cur)
{
_RotateL(grandpa);
parent->_color = BLACK;
grandpa->_color = RED;
}
if (grandpa->_left == parent&&parent->_right == cur)
{
_RotateLR(grandpa);
cur->_color = BLACK;
grandpa->_color = RED;
}
if (grandpa->_right == parent&&parent->_left == cur)
{
_RotateRL(grandpa);
cur->_color = BLACK;
grandpa->_color = RED;
}
}
_root->_color = BLACK;//每次调整完树都要把根置为黑色(性质2)
cur = parent;
parent = cur->_parent;
}
_root->_color = BLACK;
return true;
}</span><pre name="code" class="cpp"><span style="font-size:14px;">protected:
void _RotateR(Node*& parent)//右旋转
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* pNode = parent->_parent;
parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
}
subL->_right = parent;
parent->_parent = subL;
parent = subL;
subL->_parent = pNode;
if (pNode == NULL)
{
_root = subL;
}
else
{
if (pNode->_key > subL->_key)
{
pNode->_left = subL;
}
else
{
pNode->_right = subL;
}
}
}
void _RotateL(Node*& parent)//左旋转
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* pNode = parent->_parent;
parent->_right = subRL;
if (subRL)
{
subRL->_parent = parent;
}
subR->_left = parent;
parent->_parent = subR;
parent = subR;
parent->_parent = pNode;
if (pNode == NULL)
{
_root = subR;
}
else
{
if (pNode->_key > subR->_key)
{
pNode->_left = subR;
}
else
{
pNode->_right = subR;
}
}
}
void _RotateRL(Node* parent)//右左双旋
{
_RotateR(parent->_right);
_RotateL(parent);
}
void _RotateLR(Node* parent)//左右双旋
{
_RotateL(parent->_left);
_RotateR(parent);
}
protected:
Node* _root;
};</span>
博主还在研究红黑树的增删改的实现,水平有限,如有错误请多指正!!!!