红黑树总结整理
红黑色概述:
红黑树整理与AVL树类似,但在对树的平衡做控制时,AVL树会比红黑树更严格。
AVL树是通过引入平衡因子的概念进行对树高度控制。
红黑树则是对每个节点标记颜色,对颜色进行控制。
红黑树控制规则:
1.每个节点不是红色就是黑色
2.根节点必须是黑色
3.如果一个节点是红色,那么此节点的左右孩子节点必须是黑色。也就是说在一条路径上,没有连续的红色节点。
4.对任意一个节点,从该节点到其所有的NULL节点上路径的黑色节点数量均相等。
这样组合的特性是:树的最长路径不会超过最短路径的两倍。
最长路径<=2*最短路径
红黑树保证效率的方式就是遵守红黑树的4条规则。
已知红黑树从根节点到任意路径上的NULL节点中都拥有相同数量的黑色节点。
在极端情况下,一条路径全色黑色节点,我们称之为最短路径用bh表示。
又根据规则3,一个红节点它的左右两个孩子就必须是黑色节点,可以反推,一个红色节点的父亲节点是一个黑色节点。所以最长路径的组成就变成了间隔相邻的红黑节点,共有2bh个。
所以结论就为:
红黑树的高度差控制在bh<=h<=2bh
红黑树的效率:
红黑树的效率与AVL树相差无几,假设 N为红黑树的节点数量,h为最短路径。
所以求h就等于log以2为底的N。效率也就是logN级别
红黑树的插入:
红黑树的插入必须遵守四个规则。在插入空树时,根节点为黑色。而在插入非空树时,新增节点的初始颜色必须为红色。这是因为若初始颜色为黑色,会导致某一路径的黑色节点数量多于其他路径,违反规则4,并且很难维护。因此,插入时新节点的颜色应始终为红色。
当我们新插入节点为红色时,我们检查父节点,如果父节点为黑色,那么直接完成插入,如果父节点为红色,就违反了规则3,需要进行特殊处理。
先将新插入的节点标记为 c(cur),那么它的父亲为 p(parent) ,它的爷爷为g(grandfather)它的爷爷绝对是黑色节点,如果不为黑色,那么这颗红黑树早就违反了规则3.
并且还需要g节点找到并标记u(uncle)节点,也就是和p同级的兄弟节点。
情况一:变色
情况二:单旋+变色
c,p节点都为红色,那么u节点除了红色就只有存在且为黑色或不存在两种情况。
如果u节点不存在,那么c是新增节点
如果u存在且为黑色,那么c节点绝对不是叶子节点,c节点下还有子树。只不过是c节点的子树变化导致c变成了红色。
那么如何验证这个结论呢?
观察上图,如果u有节点且为黑色的话,此时就以及违反了规则4,所有路径的黑色节点数量不对等。
当u存在且为黑色的时候,C必然不是新增节点,它只可能是a或b子树里进行变换后当值c变成了红色。所以当我们在进行颜色变化的时候,需要循环向上变化。只有当p节点为黑色才停止。
u不存在或u存在且为黑色时候,我们单纯变色是不行的
会发现,当我们仅仅只是变色的话,就会违反规则4,根到左路径会比根到右路径的黑色节点个数多一。
当我们u为空时候,就需要进行一次右旋,让子树达到平衡后更新p节点为黑色,g节点为红色就能确保4条规则都不触犯,并且因为p已经变成了黑色,就不需要再往上跟新节点。
当u不为空时,c子树必然有黑色节点。同样的我们进行右旋后,将p变为黑色,g变成红色后还是遵守着4条规则。
这里也仅仅介绍右旋的情况,如果是在左边的话就同理进行左旋加变色,
情况三:双选+变色
c节点也不会一直如我们所愿,只插入在绝对的左边或绝对的右边,这时候就需要经过两次旋转,才能完成红黑树的变化。
当c在p的右边的时候就必须要通过双选,当c转完两次的时候,c来到最上层,此时将c节点变为黑色,将g节点变为红色,c又恰好为上层节点,就可以直接退出循环。
当u不为空且为黑色时
同样的,u为黑色那么c节点肯定不是新插入的节点,c原本为黑色节点。因为新插入的节点在c的子树内,导致子树的变化影响了C节点从黑色变为红色才发生的双选+变色。
最后戳了c在左子树,c的情况也会在右子树出现,所实现的方法也是也要的,并不需要特别说明举例。
以下是红黑树的代码
#pragma once
#include<iostream>
using namespace std;
enum Color { red ,black };
template<class K, class V>
struct TreeNode
{
pair<K, V> _val;
TreeNode* _left;
TreeNode* _right;
TreeNode* _parent;
Color _col;
TreeNode(const pair<K, V>& val)
:_val(val)
,_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_col(red)
{}
};
template<class K,class V>
class RBTree
{
typedef TreeNode<K, V> Node;
public:
bool Insert(const pair<K,V> &val)
{
if(_root==nullptr)
{
_root = new Node(val);
_root->_col = black;
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
parent = cur;
if(cur->_val.first>val.first)
{
cur = cur->_left;
}
else if (cur->_val.first < val.first)
{
cur = cur->_right;
}
else
{
return false;
}
}
cur = new Node(val);
if (parent->_val.first>cur->_val.first)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
//判断红黑树是否要更新
while (parent&&parent->_col!=black)
{
Node* grandfather = parent->_parent;
Node* uncle;
if (grandfather->_left==parent)
{
uncle = grandfather->_right;
if (uncle&&uncle->_col==red)//情况一:只变色
{
grandfather->_col = red;
uncle->_col = parent->_col = black;
cur = grandfather;
parent = cur->_parent;
}
else
{
if (parent->_left==cur)//情况二:单旋+变色
{
TurnR(grandfather);
grandfather->_col = red;
parent->_col = black;
break;
}
else//情况三:双循+变色
{
TurnL(parent);
TurnR(grandfather);
cur->_col = black;
grandfather->_col = red;
break;
}
}
}
else
{
uncle = grandfather->_left;
if (uncle && uncle->_col == red)//情况一:只变色
{
grandfather->_col = red;
uncle->_col = parent->_col = black;
cur = grandfather;
parent = cur->_parent;
}
else
{
if (parent->_right == cur)//情况二:单旋+变色
{
TurnL(grandfather);
grandfather->_col = red;
parent->_col = black;
break;
}
else//情况三:双循+变色
{
TurnR(parent);
TurnL(grandfather);
cur->_col = black;
grandfather->_col = red;
break;
}
}
}
}
_root->_col = black;
}
bool Check(Node*_root,int ibnum,const int rnum)
{
if (_root==nullptr)
{
if (ibnum != rnum)
{
cout << "存在黑色结点的数量不相等的路径" << endl;
return false;
}
return true;
}
if (_root->_col==red&&_root->_parent->_col==red)
{
cout << _root->_val.first<< "存在连续的红色结点" << endl;
return false;
}
if (_root->_col==black)
{
++ibnum;
}
return Check(_root->_left, ibnum, rnum) && Check(_root->_right, ibnum, rnum);
}
bool IsBalance()
{
if (_root==nullptr||_root->_col==red)
{
return false;
}
int rnum = 0;
Node* cur = _root;
while (cur)
{
if (cur->_col == black)
rnum++;
cur = cur->_left;
}
return Check(_root, 0, rnum);
}
// blackNum 根到当前结点的黑色结点的数量
//bool Check(Node* root, int blackNum, const int refNum)
//{
// if (root == nullptr)
// {
// // 前序遍历走到空时,意味着一条路径走完了
// //cout << blackNum << endl;
// if (refNum != blackNum)
// {
// cout << "存在黑色结点的数量不相等的路径" << endl;
// return false;
// }
// return true;
// }
// // 检查孩子不太方便,因为孩子有两个,且不一定存在,反过来检查父亲就方便多了
// if (root->_col == red && root->_parent->_col == red)
// {
// cout << root->_val.first << "存在连续的红色结点" << endl;
// return false;
// }
// if (root->_col == black)
// {
// blackNum++;
// }
// return Check(root->_left, blackNum, refNum)
// && Check(root->_right, blackNum, refNum);
//}
//bool IsBalance()
//{
// if (_root == nullptr)
// return true;
// if (_root->_col == red)
// return false;
// // 参考值
// int refNum = 0;
// Node* cur = _root;
// while (cur)
// {
// if (cur->_col == black)
// {
// ++refNum;
// }
// cur = cur->_left;
// }
// return Check(_root, 0, refNum);
//}
void InOrder()
{
_InOrder(_root);
}
protected:
void _InOrder(Node*cur)
{
if (cur==nullptr)
{
return;
}
_InOrder(cur->_left);
cout << "first:" << cur->_val.first << " second:" << cur->_val.second << endl;
_InOrder(cur->_right);
}
void TurnR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
subL->_right = parent;
if (subLR)
{
subLR->_parent = parent;
}
Node* Pparent = parent->_parent;
parent->_parent = subL;
if (Pparent)
{
if (Pparent->_left == parent)
{
Pparent->_left = subL;
}
else
{
Pparent->_right = subL;
}
}
subL->_parent = parent;
}
void TurnL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
subR->_left = parent;
if (subRL) { subRL->_parent = parent; }
Node* Pparent = parent->_parent;
parent->_parent = subR;
if (Pparent)
{
if (Pparent->_left == parent)
{
Pparent->_left = subR;
}
else
{
Pparent->_right = subR;
}
}
subR->_parent = parent;
}
private:
Node* _root=nullptr;
};
封装map与set:
在map与set中都是对底层的红黑树进行上层的封装。
封装后的红黑树:
#pragma once
#include<iostream>
using namespace std;
enum color
{
red,
black
};
template<class T>
struct TreeNode
{
TreeNode(const T&ky)
:_ky(ky)
,_col(red)
,_parent(nullptr)
,_left(nullptr)
,_right(nullptr)
{}
T _ky;
color _col;
TreeNode* _parent;
TreeNode* _left;
TreeNode* _right;
};
template<class T, class Ref,class Ptr >
struct Tree_Iterator
{
typedef TreeNode<T> Node;
typedef Tree_Iterator<T,Ref,Ptr> Self;
Tree_Iterator(Node* node, Node* root)
:_node(node)
, _root(root)
{}
Ref operator *()
{
return _node->_ky;
}
Ptr operator ->()
{
return &_node->_ky;
}
Self&operator++()
{
if (_node->_right)
{
Node* minleft = _node->_right;
while (minleft->_left)
{
minleft = minleft->_left;
}
_node = minleft;
}
else
{
Node* cur = _node;
Node* parent = cur->_parent;
while (parent&&parent->_right==cur)
{
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
Self &operator --()
{
if (_node==nullptr)
{
Node* cur = _root;
while (cur&&cur->_right)
{
cur = cur->_right;
}
_node = cur;
}
else if (_node->_left)
{
Node* maxright = _node->_left;
while (maxright->_right)
{
maxright = maxright->_right;
}
_node = maxright;
}
else
{
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && parent->_left == cur)
{
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
bool operator !=(const Self&kv )
{
return _node != kv._node;
}
bool operator ==(const Self& kv)
{
return _node == kv._node;
}
Node* _node;
Node* _root;
};
template<class K,class T,class KeyOFT>
class RBTree
{
typedef TreeNode<T> Node;
public:
typedef Tree_Iterator<T,T&,T*> Iterator;
typedef Tree_Iterator<T, const T&, const T*> Const_Iterator;
Iterator Begin()
{
Node* cur = _root;
while (cur&&cur->_left)
{
cur = cur->_left;
}
return Iterator(cur, _root);
}
Iterator End()
{
return Iterator(nullptr, _root);
}
Const_Iterator CBegin()const
{
Node* cur = _root;
while (cur && cur->_left)
{
cur = cur->_left;
}
return Iterator(cur, _root);
}
Const_Iterator CEnd()const
{
return Iterator(nullptr, _root);
}
pair<Iterator,bool> Insert(const T&ky)
{
if(!_root)
{
_root = new Node(ky);
_root->_col = black;
return make_pair(Iterator(_root,_root),true);
}
Node* cur = _root;
Node* parent = nullptr;
KeyOFT kot;
while (cur)
{
if (kot(cur->_ky) > kot(ky))
{
parent = cur;
cur = cur->_left;
}
else if (kot(cur->_ky) < kot(ky))
{
parent = cur;
cur = cur->_right;
}
else
{
return make_pair(Iterator(cur, _root), false);;
}
}
cur = new Node(ky);
Node* node = cur;
if (kot(parent->_ky)>kot(cur->_ky))
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
while (parent&&parent->_col==red)
{
Node* garendparent = parent->_parent;
Node* uncle;
if (garendparent->_left==parent)//只变色
{
uncle = garendparent->_right;
if (uncle&&uncle->_col==red)
{
uncle->_col = parent->_col = black;
garendparent->_col = red;
cur = garendparent;
parent = cur->_parent;
}
else
{
if (parent->_left==cur)//单选变色
{
TurnR(garendparent);
parent->_col = black;
cur->_col = garendparent->_col = red;
break;
}
else//双旋变色
{
TurnL(parent);
TurnR(garendparent);
cur->_col = black;
parent->_col = garendparent->_col = red;
break;
}
}
}
else
{
uncle = garendparent->_left;
if (uncle && uncle->_col == red)
{
uncle->_col = parent->_col = black;
garendparent->_col = red;
cur = garendparent;
parent = cur->_parent;
}
else
{
if (parent->_right == cur)//单选变色
{
TurnL(garendparent);
parent->_col = black;
cur->_col = garendparent->_col = red;
break;
}
else//双旋变色
{
TurnR(parent);
TurnL(garendparent);
cur->_col = black;
parent->_col = garendparent->_col = red;
break;
}
}
}
}
_root->_col = black;
return make_pair(Iterator(node, _root), true);
}
Node*Find(const K &val)
{
Node* cur = _root;
KeyOFT kot;
while (cur)
{
if (kot(cur->_ky) > val)
{
cur = cur->_left;
}
else if (kot(cur->_ky) < val)
{
cur = cur->_right;
}
else
{
return cur;
}
}
return nullptr;
}
private:
void TurnR(Node*parent)
{
KeyOFT kot;
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if(subLR)
{
subLR->_parent = parent;
}
subL->_right = parent;
Node* Pparent = parent->_parent;
parent->_parent = subL;
if (!Pparent)
{
subL->_parent = nullptr;
_root = subL;
}
else
{
if (kot(Pparent->_ky)> kot(subL->_ky))
{
Pparent->_left = subL;
}
else
{
Pparent->_right = subL;
}
subL->_parent = Pparent;
}
}
void TurnL(Node*parent)
{
KeyOFT kot;
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
{
subRL->_parent = parent;
}
subR->_left = parent;
Node* Pparent = parent->_parent;
parent->_parent = subR;
if (!Pparent)
{
subR->_parent = nullptr;
_root = subR;
}
else
{
if (kot(Pparent->_ky) > kot(subR->_ky))
{
Pparent->_left = subR;
}
else
{
Pparent->_right = subR;
}
subR->_parent = Pparent;
}
}
Node* _root = nullptr;
};
对于map与set在底层用的都是同一颗红黑树,只是通过类模板进行了实例化两份,所以在红黑树的自身的封装中需要改动以下措施:
1.树节点存储的值只用一个T类,因为编译器不知道要存的是Key模型,还是pair模型。
2.为红黑树添加迭代器,map与set都支持迭代器访问数据。需要重点注意的是迭代器的++与迭代器的--,这也是封装后的红黑树的重点
Self& operator++()
(前置递增)
-
当前节点有右子树:
-
找到右子树中的最左节点(即右子树中的最小节点),该节点即为当前节点的后继。
-
例如,若当前节点为
A
,右子树为C
,则后继是C
的最左子节点(假设为D
)
if (_node->_right) { Node* minleft = _node->_right; while (minleft->_left) { minleft = minleft->_left; } _node = minleft; }
-
-
当前节点无右子树:
-
从当前节点向上回溯,找到第一个祖先节点,使得当前节点位于该祖先节点的左子树中。
-
例如,若当前节点为
E
,其父节点为B
,祖父节点为A
,则A
是E
的后继。
else { Node* cur = _node; Node* parent = cur->_parent; while (parent && parent->_right == cur) { cur = parent; parent = parent->_parent; } _node = parent; // 找到的祖先节点即为后继
-
Self& operator--()
(前置递减)
-
当前节点为
nullptr
(如end()
迭代器):-
找到树中的最右节点(即最大值节点),作为前驱。
-
例如,若树为
A(B(D, E), C)
,则最右节点为C
。
if (_node == nullptr) { Node* cur = _root; while (cur && cur->_right) { cur = cur->_right; } _node = cur; // 指向最大值节点 }
-
-
当前节点有左子树:
-
找到左子树中的最右节点(即左子树中的最大节点),该节点即为当前节点的前驱。
-
例如,若当前节点为
A
,左子树为B
,则前驱是B
的最右子节点E
。
else if (_node->_left) { Node* maxright = _node->_left; while (maxright->_right) { maxright = maxright->_right; } _node = maxright; }
-
还需要注意对于为什么有KeyOFT,是因为我们红黑树在插入时需要进行比较大小,而map插入的是一个pair,而set插入的就只是Key。红黑树本身是并不知道该拿什么进行比较。所以这里传入一个KeyOFT,是上层map或set传入的一个函数模板,map就通过类模板过滤进行pair的first进行比较,set通过自身类模板比较的还是Key。
封装map:
map的封装也并没有太大难度,上述写道的类模板比较需要自己写,并且在定义成员变量红黑树的时,第二个类模板应传入的是pair,而不是V。并且map是支持运算符重载[ ],所以我们这里也同样支持,其余的也只是对红黑树的再一次调用。
#pragma once
#include"RBTree.h"
namespace cat
{
template<class K,class V >
class mymap
{
struct MapOFT
{
const K &operator ()(const pair<K, V>& kv)
{
return kv.first;
}
};
public:
typedef typename RBTree<K, pair<const K, V>, MapOFT>::Iterator iterator;
typedef typename RBTree<K, pair<const K,const V>, MapOFT>::Const_Iterator const_iterator;
pair<iterator, bool> insert(const pair<K,V> &kv)
{
return _rbt.Insert(kv);
}
iterator begin()
{
return _rbt.Begin();
}
iterator end()
{
return _rbt.End();
}
const_iterator cbegin() const
{
return _rbt.CBegin();
}
const_iterator cend()const
{
return _rbt.CEnd();
}
V& operator[](const K&ky)
{
pair<iterator, bool> ret = _rbt.Insert({ ky,V() });
return ret.first->second;
}
private:
RBTree< K, pair<const K,V>, MapOFT> _rbt;
};
void test_map()
{
mymap<int, int> m;
m.insert({ 1,1 });
m.insert({ 5,5 });
m.insert({ 2,2 });
m.insert({ 6,6 });
mymap<int, int>::iterator it = m.begin();
while (it != m.end())
{
//it->first += 1;
it->second += 1;
cout << it->first << ":" << it->second << endl;
++it;
}
mymap<string, string> dict;
dict.insert({ "sort", "排序" });
dict.insert({ "left", "左边" });
dict.insert({ "right", "右边" });
dict["left"] = "左边,剩余";
dict["insert"] = "插入";
dict["string"];
for (auto& kv : dict)
{
cout << kv.first << " " << kv.second << endl;
}
cout << endl;
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
"苹果", "香蕉", "苹果", "香蕉" };
mymap<string, int> countMap;
for (const auto& str : arr)
{
countMap[str]++;
}
for (const auto& e : countMap)
{
cout << e.first << ":" << e.second << endl;
}
cout << endl;
}
}
封装Set
#pragma once
#include"RBTree.h"
namespace cat
{
template<class K>
class myset
{
struct SetOFT
{
const K& operator()(const K& ky)
{
return ky;
}
};
public:
typedef typename RBTree<K, K, SetOFT>::Iterator iterator;
typedef typename RBTree<K, K, SetOFT>::Const_Iterator const_iterator;
pair<iterator,bool> insert(const K& ky)
{
return _rbt.Insert(ky);
}
iterator begin()
{
return _rbt.Begin();
}
iterator end()
{
return _rbt.End();
}
const_iterator begin() const
{
return _rbt.CBegin();
}
const_iterator end() const
{
return _rbt.CEnd();
}
private:
RBTree<K, K, SetOFT> _rbt;
};
void test_set()
{
myset<int> s;
/*s.insert(4);
s.insert(1);
s.insert(5);
s.insert(3);*/
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
for (auto e : a)
{
if(e==14)
{
int x = 1;
}
s.insert(e);
}
myset<int>::iterator it = s.begin();
// *it += 10;
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
it = s.end();
while (it != s.begin())
{
--it;
cout << *it << " ";
}
cout << endl;
}
}