红黑树(RBT)的定义:它或者是一颗空树,或者是具有一下性质的二叉查找树:
1.节点非红即黑。
2.根节点是黑色。
3.所有NULL结点称为叶子节点,且认为颜色为黑。
4.所有红节点的子节点都为黑色。
5.从任一节点到其叶子节点的所有路径上都包含相同数目的黑节点。
上面的定义理解起来有点费解,所以我总结了以下三点,只要满足以下三点就可以是红黑树了。
1.根节点必须是黑树
2.红树不能连续链接,黑树可以。
3.每条路径上黑树的个数必须是相同的。
插入操作(Insert)
由于性质的约束:插入点不能为黑节点,应插入红节点。因为你插入黑节点将破坏性质5,所以每次插入的点都是红结点,但是若他的父节点也为红,那就会破坏了性质4,所以要做一些“旋转”和一些节点的变色!另外为叙述方便,我们给要插入的节点分别定义如下:
N(红色),父节点为P,祖父节点为G,叔节点为U
下边将一一列出所有插入时遇到的情况:
情况一:该树为空树,直接插入根结点的位置,违反性质1,把节点颜色有红改为黑即可。
情况二:插入节点N的父节点P为黑色,不违反任何性质,无需做任何修改。
情况三:N为红,P为红,(祖节点一定存在,且为黑,下边同理)U也为红,这里不论P是G的左孩子,还是右孩子;不论N是P的左孩子,还是右孩子。如下图所示:
操作:先把P和U变为黑色,然后G变为红色
情况四:N为红,P为红,U为黑,P为G的左孩子,N为P的左孩子(或者P为G的右孩子,N为P的左孩子;反正就是同向的)如下图所示:
操作:将P变黑,G变红,然后以p为轴右旋
情况五:N为红,P为红,U为黑,P为G的左孩子,N为P的右孩子(或者P为G的右孩子,N为P的左孩子;反正两方向相反)。如下图所示:
操作:首先以P为轴左旋,然后将p和N指向的地址交换,然后就转换为情况四
代码如下:
数据结构定义如下:
enum Colour
{
RED,
BLACK,
};
template<class K, class V>
struct RBTreeNode
{
// 链接结构
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
// Key/Value
K _key;
V _value;
// 颜色
Colour _col;
RBTreeNode(const K& key, const V& value, Colour col = RED)
:_left(NULL)
, _right(NULL)
, _parent(NULL)
, _col(col)
, _key(key)
, _value(value)
{}
};
操作代码如下:
template<class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
RBTree()
:_root(NULL)
{}
bool Insert(const K& key, const V& value)
{
//1.树为空
if (_root == NULL)
{
_root = new Node(key, value, BLACK);
return true;
}
// 查找位置,插入节点
Node* parent = NULL;
Node* cur = _root;
while (cur)
{
if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
cur = new Node(key, value, RED);
if (parent->_key < key)
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
// 调整
while (cur != _root && parent->_col == RED) //这两个条件说明了cur一定存在parent 和 grandfather
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
// case1
if (uncle && uncle->_col == RED) //uncle存在且uncle的颜色为红色
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else // case2/case3 //uncle不存在 或 uncle存在但颜色为黑色
{
// case3->case2
if (cur == parent->_right)
{
_RotateL(parent); //先左旋在交换
swap(cur, parent); //交换cur和parent的地址,此时cur指向parent的地址,parent指向cur的地址
}
grandfather->_col = RED;
parent->_col = BLACK;
_RotateR(grandfather); //在右旋
}
}
else //parent == grandfather->_right
{
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->_left)
{
_RotateR(parent);
swap(cur, parent);
}
grandfather->_col = RED;
parent->_col = BLACK;
_RotateL(grandfather);
}
}
}
_root->_col = BLACK;
return true;
}
void _RotateL(Node* parent) //左旋转
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL; //修改指针(1)
if (subRL)
subRL->_parent = parent;
subR->_left = parent; //修改指针(2)
subR->_parent = parent->_parent;
parent->_parent = subR;
if (subR->_parent == NULL)
{
_root = subR;
}
else
{
if (subR->_parent->_key > subR->_key)
{
subR->_parent->_left = subR; //修改指针(3)
}
else
{
subR->_parent->_right = subR;
}
}
}
void _RotateR(Node* parent) //右旋
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
}
subL->_right = parent;
subL->_parent = parent->_parent;
parent->_parent = subL;
if (subL->_parent == NULL)
{
_root = subL;
}
else
{
if (subL->_parent->_key > subL->_key)
{
subL->_parent->_left = subL;
}
else
{
subL->_parent->_right = subL;
}
}
}
void InOrder()
{
return _InOrder(_root);
}
void _InOrder(Node* root)
{
if (root == NULL)
{
return;
}
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
protected:
Node* _root;
};
以上仅是红黑树的插入操作和打印操作,希望以上代码能帮助到想学编程的童鞋。