文章目录
前言
上一个博客总结了AVL树,链接: AVL树实现.
但是当需要大量增删的时候,AVL树旋转次数太多,效率并不高。所以我们引入了红黑树,红黑树不是绝对的平衡二叉树,但实现起来简单易懂,效率也高。实际中,红黑树也用的较多。
一、红黑树是什么?
红黑树:是一颗平衡二叉树,每个结点都有一个增加存储位来表示他的颜色,可以是红色或者黑色。根据他的特性,红黑树确保没有一条路径是其他路径的二倍。
二、红黑树的特性
1.根节点是黑色的
2.叶子节点(null)是黑色的
3.每个结点不是黑色就是红色
4.一个结点是红色的,他的两个子节点一定是黑色的
5.对于每个结点,从该节点到所有后代叶节点的简单路径上,均包含相同数目的黑节点
三、红黑树的实现
#pragma once
enum Colour
{
BLACK,
RED,
};
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Colour _col;
RBTreeNode(const T& data)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(RED)
{}
};
template<class T, class Ref, class Ptr>
struct __TreeIterator
{
typedef RBTreeNode<T> Node;
typedef __TreeIterator<T, Ref, Ptr> Self;
Node* _node;
__TreeIterator(Node* node)
:_node(node)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
Self& operator++()
{
// 1、如果右不为空,中序的下一个就是右子树的最左节点
// 2、如果右为空,表示_node所在的子树已经访问完成,在一个节点在他的祖先中找
// 沿着路径往上找孩子是它的左的那个祖先
if (_node->_right)
{
Node* subLeft = _node->_right;
while (subLeft->_left)
{
subLeft = subLeft->_left;
}
_node = subLeft;
}
else
{
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_right)
{
cur = cur->_parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
Self& operator--()
{
// ...
return *this;
}
bool operator!=(const Self& s)
{
return _node != s._node;
}
bool operator==(const Self& s)
{
return _node == s._node;
}
};
template<class K, class T, class KOfT>
class RBTree
{
typedef RBTreeNode<T> Node;
public:
typedef __TreeIterator<T, T&, T*> iterator;
typedef __TreeIterator<T, const T&, const T*> const_iterator;
iterator begin()
{
Node* cur = _root;
while (cur && cur->_left)
{
cur = cur->_left;
}
return iterator(cur);
}
iterator end()
{
return iterator(nullptr);
}
pair<iterator, bool> Insert(const T& data)
{
// 1、按搜索树的规则进行插入
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
return make_pair(iterator(_root), true);
}
KOfT koft;
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (koft(cur->_data) < koft(data))
{
parent = cur;
cur = cur->_right;
}
else if (koft(cur->_data) > koft(data))
{
parent = cur;
cur = cur->_left;
}
else
{
return make_pair(iterator(cur), false);
}
}
cur = new Node(data);
Node* newnode = cur;
if (koft(parent->_data) < koft(cur->_data))
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
// 新增节点红的
cur->_col = RED;
while (parent && parent->_col == RED)
{
Node* grandparent = parent->_parent;
if (grandparent->_left == parent)
{
Node* uncle = grandparent->_right;
if (uncle&&uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandparent->_col = RED;
cur = grandparent;
parent = cur->_parent;
}
else
{
if (cur == parent->_right)
{
RotateL(parent);
swap(parent, cur);
}
RotateR(grandparent);
grandparent->_col = RED;
parent->_col = BLACK;
break;
}
}
else
{
Node* uncle = grandparent->_left;
// 情况1:uncle存在,且为红
// 情况2 or 情况3:uncle不存在 or uncle存在,且为黑
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandparent->_col = RED;
cur = grandparent;
parent = cur->_parent;
}
else
{
if (cur == parent->_left)
{
RotateR(parent);
swap(parent, cur);
}
RotateL(grandparent);
grandparent->_col = RED;
parent->_col = BLACK;
}
}
}
_root->_col = BLACK;
return make_pair(iterator(newnode), true);
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
subR->_left = parent;
Node* ppNode = parent->_parent;
parent->_parent = subR;
// 1、原来parent是这颗树的跟,现在subR是根
// 2、parent为根的树只是整颗树中的子树,改变链接关系,那么subR要顶替他的位置
if (_root == parent)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
ppNode->_left = subR;
else
ppNode->_right = subR;
subR->_parent = ppNode;
}
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
Node* ppNode = parent->_parent;
parent->_parent = subL;
if (_root == parent)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
ppNode->_left = subL;
else
ppNode->_right = subL;
subL->_parent = ppNode;
}
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_InOrder(root->_right);
}
void InOrder()
{
_InOrder(_root);
}
bool IsValidRBTree()
{
Node* pRoot = _root;
// 空树也是红黑树
if (nullptr == pRoot)
return true;
// 检测根节点是否满足情况
if (BLACK != pRoot->_col)
{
cout << "违反红黑树性质二:根节点必须为黑色" << endl;
return false;
}
// 获取任意一条路径中黑色节点的个数
size_t blackCount = 0;
Node* pCur = pRoot;
while (pCur)
{
if (BLACK == pCur->_col)
blackCount++;
pCur = pCur->_left;
}
// 检测是否满足红黑树的性质,k用来记录路径中黑色节点的个数
size_t k = 0;
return _IsValidRBTree(pRoot, k, blackCount);
}
bool _IsValidRBTree(Node* pRoot, size_t k, const size_t blackCount)
{
//走到null之后,判断k和black是否相等
if (nullptr == pRoot)
{
if (k != blackCount)
{
cout << "违反性质四:每条路径中黑色节点的个数必须相同" << endl;
return false;
}
return true;
}
// 统计黑色节点的个数
if (BLACK == pRoot->_col)
k++;
// 检测当前节点与其双亲是否都为红色
Node* pParent = pRoot->_parent;
if (pParent && RED == pParent->_col && RED == pRoot->_col)
{
cout << "违反性质三:没有连在一起的红色节点" << endl;
return false;
}
return _IsValidRBTree(pRoot->_left, k, blackCount) &&
_IsValidRBTree(pRoot->_right, k, blackCount);
}
iterator Find(const K& key)
{
KOfT koft;
Node* cur = _root;
while (cur)
{
if (koft(cur->_data) < koft(data))
{
cur = cur->_right;
}
else if (koft(cur->_data) > koft(data))
{
cur = cur->_left;
}
else
{
return iterator(cur);
}
}
return iterator(nullptr);
}
private:
Node* _root = nullptr;
};
四、map底层的实现代码测试
#pragma once
#include "rbtree.h"
namespace bit
{
template<class K, class V>
class map
{
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
public:
typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
iterator begin()
{
return _t.begin();
}
iterator end()
{
return _t.end();
}
pair<iterator, bool> Insert(const pair<K, V>& kv)
{
return _t.Insert(kv);
}
V& operator[](const K& key)
{
pair<iterator, bool> ret = _t.Insert(make_pair(key, V()));
return ret.first->second;
}
private:
RBTree<K, pair<K, V>, MapKeyOfT> _t;
};
void test_map()
{
/*map<int, int> m;
m.Insert(make_pair(1, 1));
m.Insert(make_pair(3, 3));
m.Insert(make_pair(10, 10));
m.Insert(make_pair(5, 5));
m.Insert(make_pair(6, 6));
map<int, int>::iterator it = m.begin();
while (it != m.end())
{
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
for (auto kv : m)
{
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;*/
string strs[] = { "西瓜", "樱桃", "西瓜", "苹果", "西瓜", "西瓜", "西瓜", "苹果" };
map<string, int> countMap;
for (auto& str : strs)
{
// 1、如果水果不在map中,则operator[]会插入pair<str, 0>, 返回映射对象(次数)的引用进行了++。
// 2、如果水边在map中,则operator[]返回水果对应的映射对象(次数)的引用,对它++。
countMap[str]++;
}
for (auto kv : countMap)
{
cout << kv.first << ":" << kv.second << endl;
}
}
}
五、set底层的实现代码测试
#pragma once
#include "rbtree.h"
namespace bit
{
template<class K>
class set
{
struct SetKeyOfT
{
const K& operator()(const K& k)
{
return k;
}
};
public:
typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;
iterator begin()
{
return _t.begin();
}
iterator end()
{
return _t.end();
}
pair<iterator, bool> Insert(const K& k)
{
return _t.Insert(k);
}
private:
RBTree<K, K, SetKeyOfT> _t;
};
void test_set()
{
set<int> s;
s.Insert(3);
s.Insert(4);
s.Insert(1);
s.Insert(2);
s.Insert(5);
set<int>::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
}
总结
红黑树和AVL树都是高效的平衡二叉树,复杂度都一样。红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。