一
红黑树:首先红黑树是一颗搜索二叉树,树中的每个结点不是红色就是黑色。它的特征如下:
1.根节点是黑色
2.每个结点不是黑色就是红色
3.不能有两个连续的红结点
4.每条路径上黑色结点数量相同
二
为什么要有红黑树?
最开始我们学习了搜索二叉树,但是搜索二叉树有可能出现单链的情况,之后我们又引入了AVL树,AVL树是一种高度平衡的二叉搜索树。能够满足增加,删除,查找都是o(lg N)的时间复杂度,为什莫还要引入红黑树呢?
这时由于AVL树是高度平衡二叉搜索树,维持一颗AVL树的代价相比红黑树要大很多,由于它的高度平衡,使得几乎每次插入或者删除都要调整树。而红黑树是一颗近似平衡的二叉搜索树,它满足最长路径不超过最短路径的两倍,易于维护。而且红黑树效率最短路径lgN,最长路径2LgN
三
思考为什莫红黑树满足它的性质,就能保证最长路径不超过最短路径的两倍。。。最短,全黑,最长,每个黑的中间加个红
最多也就二倍,因此保证了最长路径不超过最短路径的两倍
四 插入
一般默认插入的结点是红的(如果黑的,每条路径上都要增加)
1.如果要插入的结点是根节点,则直接插入,并将根节点染为黑色
2.如果插入位置父亲是黑色,直接插入
3.如果要插入位置的父亲是红色的,这时如果再插入一个红色结点,就会出现两个连续的红色结点。
假如要插入的结点是cur,它的父亲是parent,它的父亲的兄弟是uncle,它的祖父是grandfather.
分为两种情况1.叔叔存在且为红
2.叔叔不存在,或者叔叔为黑
#pragma once
#include<iostream>
using namespace std;
enum color
{
RED,
BLACK
};
template<class K,class V>
struct RBTreeNode
{
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>*_right;
RBTreeNode<K, V>*_parent;
K _key;
V _value;
color _cor;
RBTreeNode (const K&key,const V&value )
:_left ( NULL )
, _right ( NULL )
, _parent (NULL )
, _key (key )
, _value (value)
, _cor (RED )
{}
};
template<class K,class V>
class RBTree
{public:
typedef RBTreeNode<K, V> Node;
RBTree ( )
:_Root ( NULL )
{}
bool Insert ( const K& key, const V& value )
{
if ( _Root == NULL )
{
_Root = new Node ( key, value );
_Root->_cor = BLACK;
return true;
}
Node* cur = _Root;
Node* parent = NULL;
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 );
if ( parent->_key > key )
{
parent->_left = cur;
cur->_parent = parent;
}
else
{
parent->_right = cur;
cur->_parent = parent;
}
//检查
//1.parent为黑
//2.parent为红,叔叔存在且为红
//3.parent为红,叔叔不存在,或者叔叔存在且为黑
while (parent&& parent->_cor == RED )
{
Node* Grandfather = parent->_parent;
if ( parent == Grandfather->_left )
{
Node* uncle = Grandfather->_right;
if( uncle&&uncle->_cor == RED)//叔叔存在且为红色
{
uncle->_cor = parent->_cor = BLACK;
Grandfather->_cor = RED;//继续往上调
cur = Grandfather;
parent = cur->_parent;
}
else//叔叔不存在或者叔叔等于黑
{ //双旋
if ( cur == parent->_right )
{
RotateL (parent );
swap(parent, cur);
}
//单旋
RotateR ( Grandfather );
parent->_cor = BLACK;
Grandfather->_cor = RED;
}
}
else
{
Node* uncle = Grandfather->_left;
if ( uncle&&uncle->_cor == RED )//叔叔存在且为红
{
parent->_cor = uncle->_cor = BLACK;
Grandfather->_cor = RED;//继续向上调整
cur = Grandfather;
parent = cur->_parent;
}
else//叔叔不存在,或者叔叔存在且为黑
{
if ( cur == parent->_left )
{
RotateR ( parent );
swap(parent, cur);
}
RotateL ( Grandfather );
Grandfather->_cor = RED;
parent->_cor = BLACK;
}
}
}
_Root->_cor = BLACK;
return true;
}
void RotateR ( Node*parent )
{
Node*subL = parent->_left;
Node* subLR = subL->_right;
Node*ppNode = parent->_parent;
parent->_left = subLR;
if ( subLR )
{
subLR->_parent = parent;
}
subL->_right = parent;
parent->_parent = subL;
if ( ppNode == NULL )
{
_Root = subL;
_Root->_parent = NULL;
}
else
{
if ( ppNode->_left == parent )
ppNode->_left = subL;
else
ppNode->_right = subL;
subL->_parent = ppNode;
}
}
void RotateL ( Node*parent )
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* ppNode = parent->_parent;
parent->_right = subRL;
if ( subRL )
{
subRL->_parent = parent;
}
subR->_left = parent;
parent->_parent = subR;
if ( ppNode == NULL )
{
_Root = subR;
_Root->_parent = NULL;
}
else if ( ppNode->_left == parent )
{
ppNode->_left = subR;
}
else
{
ppNode->_right = subR;
}
subR->_parent == ppNode;
}
void Inorder ( )
{
_Inorder ( _Root );
cout << endl;
}
void _Inorder ( Node*Root )
{
if (Root == NULL )
{
return ;
}
_Inorder ( Root->_left );
cout << Root -> _key << " ";
_Inorder ( Root->_right );
}
bool Isbalance ( )//判断是否平衡 //首先我们会想到拿高度判断,最长不超多最短二倍 但是颜色可能不符合,因此不能仅仅拿高度来判断
//判断:1.根是黑的 2.没有连续红色结点 (递归遍历) 3.每条路径上黑色结点数目相等
{
if ( _Root->_cor == RED )
{
return false;
}
int k = 0;
int blacknum = 0;
Node* cur = _Root;
while ( cur )
{
if ( cur->_cor == BLACK )
{
k++;
}
cur = cur->_left;
}
return _IsBalance ( _Root,k,blacknum );
}
private://注意此处blacknum不能给引用
bool _IsBalance ( Node* cur, const int& k,int blacknum )//想想我们如何判断每个路径上黑色结点数量相同 有的人会说用容器存 空间复杂度 即为最后一层结点数 2^(log 2 N)-1 也就是O(N)显然是不行的
{
//因此我们不妨先把最左边,或者最右边一条路径上黑节点算出来,然后和其他路径上对比,如果有不同,说明每条路径上黑色结点树不同
if ( cur == NULL )
{
if ( blacknum != k )
{
cout << "黑节点数目不想等" << " " << endl;
return false;
}
else
{
return true;
}
}
Node* parent = cur->_parent;
if (( cur->_cor == RED)&&(parent->_cor == RED ))//注意,一般我们会想如何判断没有连续红节点,回想着判断它的左右孩子是否为红。这样还要考虑左孩子,右孩子
{ //此处 我们不妨逆着来想,反正每个结点会被遍历到,判断它的父亲是否为红。
cout << "存在连续的红色结点" << cur->_key << endl;
return false;
}
if ( cur->_cor == BLACK )
{
blacknum++;
}
return _IsBalance ( cur->_left, k, blacknum ) && _IsBalance ( cur->_right, k, blacknum );
}
private:
Node* _Root;
};
void Test ( )
{
int arr[] = {16,3,7,11,9,26,18,14};
RBTree<int, int>t1;
for ( int i = 0; i < sizeof(arr) / sizeof (arr[0]); i++ )
{
t1.Insert ( arr[i],i);
cout <<arr[i]<<" "<<"Isbalance?"<< t1.Isbalance ( ) << endl;
}
t1.Inorder ();
cout<<t1.Isbalance ( )<<endl;
}