赞
踩
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black,通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的
思考:为什么满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍?
enum Color { Red, Black }; template <class K,class V> struct TreeNode { TreeNode(const pair<K, V>& kv) :_left(nullptr) ,_right(nullptr) ,_parent(nullptr) ,_kv(kv) ,_col(Red) {} TreeNode* _left; TreeNode* _right; TreeNode* _parent; pair<K, V> _kv; Color _col; };
思考:在节点的定义中,为什么要将节点的默认颜色给成红色的?
为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为跟节点必须为黑色,为了与根节点进行区分,将头结点给成黑色,并且让头结点的 pParent 域指向红黑树的根节点,pLeft域指向红黑树中最小的节点,_pRight域指向红黑树中最大的节点,如下:
红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:
先按照搜索二叉树的规则找到插入节点的位置
bool Insert(const pair<K, V>& kv) { if (_root == nullptr) { _root = new Node(kv); _root->_col = Black; return true; } Node* cur = _root; Node* parent = nullptr; while (cur) { if (cur->_kv.first > kv.first) { parent = cur; cur = cur->_left; } else if(cur->_kv.first < kv.first) { parent = cur; cur = cur->_right; } else { return false; } } if (parent->_kv.first > kv.first) { cur = new Node(kv); parent->_left = cur; cur->_parent = parent; } else { cur = new Node(kv); parent->_right = cur; cur->_parent = parent; } ******************************************************************* }
新增:插入红色节点
1、插入节点的父亲是黑色,那么就结束了。没有违反任何规则。
2、插入节点的父亲是红色的,那么存在连续的红色节点,违反规则3,需要处理
关键看叔叔uncle其他几个节点c p g三个颜色固定
约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点
因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何性质,则不需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连在一起的红色节点,此时需要对红黑树分情况来讨论:
这里大分类有两类(逻辑分类):
但实际转化为代码时,需要看cur p g u三者之间的位置关系来分类,因为不同位置调整的方式不同
在这三种位置关系的情况下,再结合逻辑分类进行分类
以下是分类逻辑图
这种情况下 uncle存在且为红色
分为两个小情况
cur在这棵树的外侧
cur在这棵树的内侧
bool Insert(const pair<K, V>& kv) { if (_root == nullptr) { _root = new Node(kv); _root->_col = Black; return true; } Node* cur = _root; Node* parent = nullptr; while (cur) { if (cur->_kv.first > kv.first) { parent = cur; cur = cur->_left; } else if(cur->_kv.first < kv.first) { parent = cur; cur = cur->_right; } else { return false; } } if (parent->_kv.first > kv.first) { cur = new Node(kv); parent->_left = cur; cur->_parent = parent; } else { cur = new Node(kv); parent->_right = cur; cur->_parent = parent; } while (parent && parent->_col == Red) { if (parent->_col == Black) { break; } //parent是红色,需要先找祖父,再寻找uncle Node* grandparent = parent->_parent; Node* uncle = nullptr; //parent在左 uncle在右 if (grandparent->_left == parent) { uncle = grandparent->_right; //uncle存在且为红色 if (uncle && uncle->_col == Red) { parent->_col = Black; uncle->_col = Black; grandparent->_col = Red; //继续向上更新 cur = grandparent; parent = cur->_parent; } //uncle存在且为黑色或者uncle不存在 else { //cur在左,右单旋 if (cur == parent->_left) { RotateR(grandparent); parent->_col = Black; grandparent->_col = Red; break; } //cur在右,双旋 else { RotateL(parent); RotateR(grandparent); cur->_col = Black; grandparent->_col = Red; break; } } } //parent在右 uncle在左 else { uncle = grandparent->_left; //uncle存在且为红色 if (uncle && uncle->_col == Red) { parent->_col = uncle->_col = Black; grandparent->_col = Red; cur = grandparent; parent = cur->_parent; } //uncle存在且为黑色或uncle不存在 else { //cur在右,左单旋 if (cur == parent->_right) { RotateL(grandparent); parent->_col = Black; grandparent->_col = Red; break; } //cur在左,双旋 else { RotateR(parent); RotateL(grandparent); cur->_col = Black; grandparent->_col = Red; break; } } } } _root->_col = Black; return true; }
根据红黑树的规则,我们可以中序遍历这棵树打印值来检验是否符合规则,但仅仅这样是不能完全检测出的,我们需要根据红黑树的规则,来设计函数来检测这棵树
规则1与2只需再开始时检测一边
规则3如果之间判断会不好判断,但我们可以转换思路,如果该节点是红色的,那么他的父节点一定是黑色的,如果是红色就是违背了规则
规则4需要在每条路径走到空的时候与参考值比较,不相等就违背规则,参考值是在调用之前算出某条路径的黑色节点数
bool Isbalance() { if (_root == nullptr) { return true; } if (_root->_col == Red) { return false; } size_t reference = 0; Node* cur = _root; while (cur) { if (cur->_col == Black) { reference++; } cur = cur->_left; } return _Isbalance(_root, reference, 0); } bool _Isbalance(Node* root, size_t reference, size_t bnum) { if (root == nullptr) { if (bnum != reference) { cout << "每条路径黑色节点个数不同" << endl; return false; } return true; } if (root->_col == Red) { if (root->_parent->_col != Black) { cout << "出现连续的红色节点" << endl; return false; } } else { bnum++; } return _Isbalance(root->_left, reference, bnum) && _Isbalance(root->_right, reference, bnum); }
RBTree.h
#include <iostream> using namespace std; enum Color { Red, Black }; template <class K,class V> struct TreeNode { TreeNode(const pair<K, V>& kv) :_left(nullptr) ,_right(nullptr) ,_parent(nullptr) ,_kv(kv) ,_col(Red) {} TreeNode* _left; TreeNode* _right; TreeNode* _parent; pair<K, V> _kv; Color _col; }; template <class K, class V> class RBTree { typedef TreeNode<K, V> Node; public: bool Insert(const pair<K, V>& kv) { if (_root == nullptr) { _root = new Node(kv); _root->_col = Black; return true; } Node* cur = _root; Node* parent = nullptr; while (cur) { if (cur->_kv.first > kv.first) { parent = cur; cur = cur->_left; } else if(cur->_kv.first < kv.first) { parent = cur; cur = cur->_right; } else { return false; } } if (parent->_kv.first > kv.first) { cur = new Node(kv); parent->_left = cur; cur->_parent = parent; } else { cur = new Node(kv); parent->_right = cur; cur->_parent = parent; } while (parent && parent->_col == Red) { if (parent->_col == Black) { break; } //parent是红色,需要先找祖父,再寻找uncle Node* grandparent = parent->_parent; Node* uncle = nullptr; //parent在左 uncle在右 if (grandparent->_left == parent) { uncle = grandparent->_right; //uncle存在且为红色 if (uncle && uncle->_col == Red) { parent->_col = Black; uncle->_col = Black; grandparent->_col = Red; //继续向上更新 cur = grandparent; parent = cur->_parent; } //uncle存在且为黑色或者uncle不存在 else { //cur在左,右单旋 if (cur == parent->_left) { RotateR(grandparent); parent->_col = Black; grandparent->_col = Red; break; } //cur在右,双旋 else { RotateL(parent); RotateR(grandparent); cur->_col = Black; grandparent->_col = Red; break; } } } //parent在右 uncle在左 else { uncle = grandparent->_left; //uncle存在且为红色 if (uncle && uncle->_col == Red) { parent->_col = uncle->_col = Black; grandparent->_col = Red; cur = grandparent; parent = cur->_parent; } //uncle存在且为黑色或uncle不存在 else { //cur在右,左单旋 if (cur == parent->_right) { RotateL(grandparent); parent->_col = Black; grandparent->_col = Red; break; } //cur在左,双旋 else { RotateR(parent); RotateL(grandparent); cur->_col = Black; grandparent->_col = Red; break; } } } } _root->_col = Black; return true; } void RotateL(Node* parent) { Node* subR = parent->_right; Node* subRL = subR->_left; parent->_right = subRL; subR->_left = parent; Node* parentparent = parent->_parent; if (subRL) subRL->_parent = parent; parent->_parent = subR; if (parent == _root) { subR->_parent = nullptr; _root = subR; } else { subR->_parent = parentparent; if (parentparent->_left == parent) { parentparent->_left = subR; } else { parentparent->_right = subR; } } } void RotateR(Node* parent) { Node* subL = parent->_left; Node* subLR = subL->_right; parent->_left = subLR; subL->_right = parent; Node* parentparent = parent->_parent; if (subLR) { subLR->_parent = parent; } parent->_parent = subL; if (parent == _root) { subL->_parent = nullptr; _root = subL; } else { subL->_parent = parentparent; if (parentparent->_left == parent) { parentparent->_left = subL; } else { parentparent->_right = subL; } } } void InOrder() { _InOrder(_root); cout << endl; } bool Isbalance() { if (_root == nullptr) { return true; } if (_root->_col == Red) { return false; } size_t reference = 0; Node* cur = _root; while (cur) { if (cur->_col == Black) { reference++; } cur = cur->_left; } return _Isbalance(_root, reference, 0); } private: void _InOrder(Node* root) { if (root == nullptr) { return; } _InOrder(root->_left); cout << root->_kv.first << " "; _InOrder(root->_right); } bool _Isbalance(Node* root, size_t reference, size_t bnum) { if (root == nullptr) { if (bnum != reference) { cout << "每条路径黑色节点个数不同" << endl; return false; } return true; } if (root->_col == Red) { if (root->_parent->_col != Black) { cout << "出现连续的红色节点" << endl; return false; } } else { bnum++; } return _Isbalance(root->_left, reference, bnum) && _Isbalance(root->_right, reference, bnum); } Node* _root = nullptr; };
RBTree.c
#include "RBTree.h" #define N 1000 int main() { srand((unsigned int)time(NULL)); RBTree<int, int> t; for (int i = 0; i < N; i++) { int sum = rand(); cout << "插入数据为" << sum; t.Insert(make_pair(sum, sum)); if (t.Isbalance()) { cout << "插入后符合规则" << endl; } else { cout << "插入后不符合规则" << endl; } } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。