赞
踩
红黑树也是一种平衡二叉搜索树,但在每个节点上增加一个存储位表示节点的颜色,颜色右两种,红与黑,因此也称为红黑树。
通过对任意一条从根到叶子的路径上各个节点着色方式的限制,红黑树可以确保没有一条路径会比其他路径长出两倍,因此是“近似平衡”。
下面就是一棵红黑树:

结合上面的图,我们可以了解下红黑树成立的各种条件:
①每个节点不是红色就是黑色
②根节点是黑色的
③如果一个节点是红色的,那么这个红色节点的两个孩子节点都是黑色的
④对于每个节点,从该节点到其所有后代叶结点的路径上,黑色节点的数量相同
⑤每个叶子节点都是黑色的(这里所说的叶子节点是上图中的空节点)
- //用枚举来标识颜色
- enum Colour
- {
- RED,
- BLACK
- };
- template<class K, class V>
- struct RBTreeNode
- {
- RBTreeNode<K, V>* _left;
- RBTreeNode<K, V>* _right;
- RBTreeNode<K, V>* _parent;
-
- pair<K, V> _kv;
- Colour _col;
-
- RBTreeNode(const pair<K, V>& kv)
- :_left(nullptr)
- , _right(nullptr)
- , _parent(nullptr)
- , _kv(kv)
- , _col(RED)
- {}
- };

- template<class K, class V>
- class RBTree
- {
- typedef RBTreeNode<K, V> Node;
- public:
-
- //此处实现各种成员函数和接口
-
- private:
- Node* _root = nullptr;
- }
基本插入也和之前的差不多,直接上代码:
- bool Insert(const pair<K, V>& kv)
- {
- if (_root == nullptr)
- {
- _root = new Node(kv);
- _root->_col = BLACK;
- return true;
- }
-
- Node* parent = nullptr;
- Node* cur = _root;
- while (cur)
- {
- if (cur->_kv.first < kv.first)
- {
- parent = cur;
- cur = cur->_right;
- }
- else if (cur->_kv.first > kv.first)
- {
- parent = cur;
- cur = cur->_left;
- }
- else
- {
- return false;
- }
- }
-
- cur = new Node(kv);
- if (parent->_kv.first < kv.first)
- {
- parent->_right = cur;
- }
- else
- {
- parent->_left = cur;
- }
- cur->_parent = parent;
- //插入完成,开始改变颜色和调整旋转
- cur->_col = RED;//把新插入的节点都搞成红色,因为如果插入后改为黑色,一定违反规则四:每条路径的黑色节点数量相同
- //如果父亲是黑色节点或者插入前是空树,直接摊牌不玩了,不进入循环
-
- while (parent && parent->_col == RED)//父节点存在且父节点为红色
- {
- //这里的循环控制平衡,具体看下面的各种情况
-
- }
- }

按搜索树的性质插入之后就是要判断红黑树的性质是否遭到破坏。
新插入节点默认为红色,因此:如果双亲节点颜色是黑色,那么没有违反红黑树的任何性质,不需要调整,就是上面代码最后的循环直接跳过;但是如果新插入的节点的双亲为红色,就违反了上面的规则“红节点的孩子为黑”,也就是出现了连续的红节点,需要调整,就是进入上面的循环部分
此时就要分下面的几条情况来讨论,维持平衡的方法的关键就是看叔叔也就是父亲的兄弟节点的状态
如下图(假设cur是新增):

uncle存在且为红时,我们直接将父节点和叔叔节点都变成黑,再将爷爷节点变为红,但是只这样做肯定不行,比如下图:

一次调整过后就会出现上面的情况,所以需要不断往上调整
如下图:

如上图,cur本身是黑色,是树中原来的节点,因为子树有新增变成了红,所以对于cur节点有两种情况符合情况一:
①本身是新增,默认新增节点为红
②子树有新增,通过情况一的向上调整变成了红
从情况一我们可以看出,cur可能是新节点也可能不是新节点,但最终结果都是变红。
如果uncle节点不存在,那么cur一定是新增,如果cur不是新增,最开始循环的条件为父节点存在且为红,又因为红节点的孩子为黑这条性质,cur必定为黑,但是由于uncle不存在,导致以爷爷节点为根的子树左右子树黑节点数量不一样。
所以如果uncle不存在,cur必定为新增,如下图:

而对于uncle节点存在且为黑时, 那么cur原来肯定是黑色的因为父节点是红的,右因为左右两边黑色节点数量要一致,cur的孩子也为红,这时候在cur孩子后面新增节点时,就变成了情况一,会不断向上调整颜色,也会把cur变成红色,如下图:

所以,情况二和情况三的最终情况都是cur为红,所以可以放在一起讨论
- bool Insert(const pair<K, V>& kv)
- {
- if (_root == nullptr)
- {
- _root = new Node(kv);
- _root->_col = BLACK;
- return true;
- }
-
- Node* parent = nullptr;
- Node* cur = _root;
- while (cur)
- {
- if (cur->_kv.first < kv.first)
- {
- parent = cur;
- cur = cur->_right;
- }
- else if (cur->_kv.first > kv.first)
- {
- parent = cur;
- cur = cur->_left;
- }
- else
- {
- return false;
- }
- }
-
- cur = new Node(kv);
- if (parent->_kv.first < kv.first)
- {
- parent->_right = cur;
- }
- else
- {
- parent->_left = cur;
- }
- cur->_parent = parent;
- //插入完成,开始改变颜色和调整旋转
- cur->_col = RED;//把新插入的节点都搞成红色,因为如果插入后改为黑色,一定违反规则四:每条路径的黑色节点数量相同
- //如果父亲是黑色节点或者插入前是空树,直接摊牌不玩了,不进入循环
-
- while (parent && parent->_col == RED)//父节点存在且父节点为红色
- {
- //找祖父
- Node* grandfather = parent->_parent;
- assert(grandfather);
- assert(grandfather->_col == BLACK);
- //红黑树的关键看叔叔,也就是父亲的兄弟
- if (parent == grandfather->_left)//父亲在爷爷的左边,叔叔分为几种情况分开讨论
- {
- Node* uncle = grandfather->_right;//父亲在左边,那么叔叔就在右边
- //情况一:uncle存在且为红
- if (uncle && uncle->_col == RED)
- {
- //父亲和叔叔变黑是为了替代祖父的黑,祖父变红是为了保持黑色节点数量不变
- parent->_col = uncle->_col = BLACK;//把父亲和叔叔变黑
- grandfather->_col = RED;//把祖父变红
- //继续往上处理 -- 将祖父当成新增节点,循环往上处理
- cur = grandfather;
- parent = cur->_parent;
- }
- //情况二+三,uncle不存在 + 存在且为黑
- else
- {
- //新增在左边:右单旋+变色
- // g p
- // p u --> c g
- //c u
- if (cur == parent->_left)
- {
- RotateR(grandfather);
- parent->_col = BLACK;
- grandfather->_col = RED;
- }
- //新增在右边:左单旋 + 右双旋+变色
- // g
- // p u -->
- // c
- else
- {
- RotateL(parent);
- RotateR(grandfather);
- cur->_col = BLACK;
- grandfather->_col = RED;
- }
- break;
- }
- }
- 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 //情况二+三,uncle不存在 + 存在且为黑
- {
- //新增在右边:左单旋+变色
- // g
- // u p
- // c
- if (cur == parent->_right)
- {
- RotateL(grandfather);
- parent->_col = BLACK;
- grandfather->_col = RED;
- }
- //新增在左边:左右双旋+变色
- // g
- // u p
- // c
- else
- {
- RotateR(parent);
- RotateL(grandfather);
- cur->_col = BLACK;
- grandfather->_col = RED;
- }
-
- break;
- }
-
- }
- }
- //循环结束
- _root->_col = BLACK;
- return true;
- }

- //左旋转函数
- void RotateL(Node* parent)
- {
- Node* subR = parent->_right;
- Node* subRL = subR->_left;
-
- parent->_right = subRL;
- //subRL可能是空
- if (subRL)
- {
- subRL->_parent = parent;
- }
- //记录一下要旋转的parent节点的_parent,用于当parent是子树根时的调整
- Node* ppNode = parent->_parent;
-
- subR->_left = parent;
- parent->_parent = subR;
-
- //parent是整棵树的根
- if (_root == parent)
- {
- _root = subR;
- subR->_parent = nullptr;
- }
- else//parent是子树的根
- {
- 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;
- //subLR可能是空
- if (subLR)
- {
- subLR->_parent = parent;
- }
- //记录一下要旋转的parent节点的_parent,用于当parent是子树根时的调整
- Node* ppNode = parent->_parent;
-
- subL->_right = parent;
- parent->_parent = subL;
-
- //parent是整颗树的根
- if (_root == parent)
- {
- _root = subL;
- subL->_parent = nullptr;
- }
- else
- {
- if (ppNode->_left == parent)
- {
- ppNode->_left = subL;
- }
- else
- {
- ppNode->_right = subL;
- }
- subL->_parent = ppNode;
- }
- }

- public:
- bool IsBalance() //根据规则来检查
- {
- if (_root && _root->_col == RED)
- {
- cout << "根节点不是黑色" << endl;
- return false;
- }
-
- //定义基准值,用来判断每条路径的黑色节点数量是否相同
- int benchmark = 0;
- Node* cur = _root;
- while (cur)
- {
- if (cur->_col == BLACK)
- {
- ++benchmark;
- }
- cur = cur->_left;
- }
-
- //检查连续红色节点
- return _Check(_root,0,benchmark);
-
- }
- private:
- bool _Check(Node* root,int blackNum,int benchmark)
- {
- if (root == nullptr)
- {
- if (benchmark != blackNum)
- {
- cout << "某条路径黑色节点数量不相等";
- return false;
- }
- return true;
- }
- if (root->_col == BLACK)
- {
- ++blackNum;
- }
- if (root->_col == RED && root->_parent && root->_parent->_col == RED)
- {
- cout << "存在连续红节点" << endl;
- return false;
- }
- return _Check(root->_left,blackNum,benchmark) && _Check(root->_right,blackNum,benchmark);
- }

- void InOrder()
- {
- _InOrder(_root);
- cout << endl;
- }
- private:
- void _InOrder(Node* root)
- {
- if (root == nullptr)
- {
- return;
- }
-
- _InOrder(root->_left);
- cout << root->_kv.first << ":" << root->_kv.second << endl;
- _InOrder(root->_right);
- }

- Node* Find(const K& key)
- {
- Node* cur = _root;
- while (cur)
- {
- if (cur->_kv.first < key)
- {
- cur = cur->_right;
- }
- else if (cur->_kv.first > key)
- {
- cur = cur->_left;
- }
- else
- {
- return cur;
- }
- }
- }

- ~RBTree()
- {
- _Destroy(_root);
- _root == nullptr;
- }
- private:
- void _Destroy(Node* root)
- {
- if (root == nullptr)
- {
- return;
- }
- _Destroy(root->_left);
- _Destroy(root->_right);
- delete root;
- root == nullptr;
- }

源代码(RBTree.h)
- #pragma once
- //最长路径不超过最短路径的两倍
-
- //红黑树和AVL树相比来说,红黑树的优点是旋转的次数更少
- //如果两个树都插入1万个树,查找时,AVL树最多要查找30次,红黑树最多查找60次
- // 但是这种差别对于CPU来说可以忽略不计,所以论综合性能,还是红黑树更胜一筹
- #include<iostream>
- #include<assert.h>
- using namespace std;
-
- //用枚举来标识颜色
- enum Colour
- {
- RED,
- BLACK
- };
- template<class K, class V>
- struct RBTreeNode
- {
- RBTreeNode<K, V>* _left;
- RBTreeNode<K, V>* _right;
- RBTreeNode<K, V>* _parent;
-
- pair<K, V> _kv;
- Colour _col;
-
- RBTreeNode(const pair<K, V>& kv)
- :_left(nullptr)
- , _right(nullptr)
- , _parent(nullptr)
- , _kv(kv)
- , _col(RED)
- {}
- };
-
- template<class K, class V>
- class RBTree
- {
- typedef RBTreeNode<K, V> Node;
- public:
- Node* Find(const K& key)
- {
- Node* cur = _root;
- while (cur)
- {
- if (cur->_kv.first < key)
- {
- cur = cur->_right;
- }
- else if (cur->_kv.first > key)
- {
- cur = cur->_left;
- }
- else
- {
- return cur;
- }
- }
- }
- ~RBTree()
- {
- _Destroy(_root);
- _root == nullptr;
- }
- //插入时和搜索树一样的插入
- bool Insert(const pair<K, V>& kv)
- {
- if (_root == nullptr)
- {
- _root = new Node(kv);
- _root->_col = BLACK;
- return true;
- }
-
- Node* parent = nullptr;
- Node* cur = _root;
- while (cur)
- {
- if (cur->_kv.first < kv.first)
- {
- parent = cur;
- cur = cur->_right;
- }
- else if (cur->_kv.first > kv.first)
- {
- parent = cur;
- cur = cur->_left;
- }
- else
- {
- return false;
- }
- }
-
- cur = new Node(kv);
- if (parent->_kv.first < kv.first)
- {
- parent->_right = cur;
- }
- else
- {
- parent->_left = cur;
- }
- cur->_parent = parent;
- //插入完成,开始改变颜色和调整旋转
- cur->_col = RED;//把新插入的节点都搞成红色,因为如果插入后改为黑色,一定违反规则四:每条路径的黑色节点数量相同
- //如果父亲是黑色节点或者插入前是空树,直接摊牌不玩了,不进入循环
-
- while (parent && parent->_col == RED)//父节点存在且父节点为红色
- {
- //找祖父
- Node* grandfather = parent->_parent;
- assert(grandfather);
- assert(grandfather->_col == BLACK);
- //红黑树的关键看叔叔,也就是父亲的兄弟
- if (parent == grandfather->_left)//父亲在爷爷的左边,叔叔分为几种情况分开讨论
- {
- Node* uncle = grandfather->_right;//父亲在左边,那么叔叔就在右边
- //情况一:uncle存在且为红
- if (uncle && uncle->_col == RED)
- {
- //父亲和叔叔变黑是为了替代祖父的黑,祖父变红是为了保持黑色节点数量不变
- parent->_col = uncle->_col = BLACK;//把父亲和叔叔变黑
- grandfather->_col = RED;//把祖父变红
- //继续往上处理 -- 将祖父当成新增节点,循环往上处理
- cur = grandfather;
- parent = cur->_parent;
- }
- //情况二+三,uncle不存在 + 存在且为黑
- else
- {
- //新增在左边:右单旋+变色
- // g p
- // p u --> c g
- //c u
- if (cur == parent->_left)
- {
- RotateR(grandfather);
- parent->_col = BLACK;
- grandfather->_col = RED;
- }
- //新增在右边:左单旋 + 右双旋+变色
- // g
- // p u -->
- // c
- else
- {
- RotateL(parent);
- RotateR(grandfather);
- cur->_col = BLACK;
- grandfather->_col = RED;
- }
- break;
- }
- }
- 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 //情况二+三,uncle不存在 + 存在且为黑
- {
- //新增在右边:左单旋+变色
- // g
- // u p
- // c
- if (cur == parent->_right)
- {
- RotateL(grandfather);
- parent->_col = BLACK;
- grandfather->_col = RED;
- }
- //新增在左边:左右双旋+变色
- // g
- // u p
- // c
- else
- {
- RotateR(parent);
- RotateL(grandfather);
- cur->_col = BLACK;
- grandfather->_col = RED;
- }
-
- break;
- }
-
- }
- }
- //循环结束
- _root->_col = BLACK;
- return true;
- }
-
- void InOrder()
- {
- _InOrder(_root);
- cout << endl;
- }
- bool IsBalance() //根据规则来检查
- {
- if (_root && _root->_col == RED)
- {
- cout << "根节点不是黑色" << endl;
- return false;
- }
-
- //定义基准值,用来判断每条路径的黑色节点数量是否相同
- int benchmark = 0;
- Node* cur = _root;
- while (cur)
- {
- if (cur->_col == BLACK)
- {
- ++benchmark;
- }
- cur = cur->_left;
- }
-
- //检查连续红色节点
- return _Check(_root,0,benchmark);
-
- }
- private:
- bool _Check(Node* root,int blackNum,int benchmark)
- {
- if (root == nullptr)
- {
- if (benchmark != blackNum)
- {
- cout << "某条路径黑色节点数量不相等";
- return false;
- }
- return true;
- }
- if (root->_col == BLACK)
- {
- ++blackNum;
- }
- if (root->_col == RED && root->_parent && root->_parent->_col == RED)
- {
- cout << "存在连续红节点" << endl;
- return false;
- }
- return _Check(root->_left,blackNum,benchmark) && _Check(root->_right,blackNum,benchmark);
- }
- //左旋转函数
- void RotateL(Node* parent)
- {
- Node* subR = parent->_right;
- Node* subRL = subR->_left;
-
- parent->_right = subRL;
- //subRL可能是空
- if (subRL)
- {
- subRL->_parent = parent;
- }
- //记录一下要旋转的parent节点的_parent,用于当parent是子树根时的调整
- Node* ppNode = parent->_parent;
-
- subR->_left = parent;
- parent->_parent = subR;
-
- //parent是整棵树的根
- if (_root == parent)
- {
- _root = subR;
- subR->_parent = nullptr;
- }
- else//parent是子树的根
- {
- 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;
- //subLR可能是空
- if (subLR)
- {
- subLR->_parent = parent;
- }
- //记录一下要旋转的parent节点的_parent,用于当parent是子树根时的调整
- Node* ppNode = parent->_parent;
-
- subL->_right = parent;
- parent->_parent = subL;
-
- //parent是整颗树的根
- 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 _Destroy(Node* root)
- {
- if (root == nullptr)
- {
- return;
- }
- _Destroy(root->_left);
- _Destroy(root->_right);
- delete root;
- root == nullptr;
- }
- private:
- Node* _root = nullptr;
- };

测试
- #include"RBTree.h"
-
- void TestRBTree1()
- {
- int a[] = { 4,2,6,1,3,5,15,7,16,14 };
- RBTree<int, int> t1;
- for (auto e : a)
- {
- t1.Insert(make_pair(e, e));
- }
- cout << "IsBalance:" << t1.IsBalance() << endl;
- }
-
- void TestRBTree2()
- {
- size_t N = 10000;
- srand(time(0));
- RBTree<int, int> t1;
- for (size_t i = 0; i < N; ++i)
- {
- int x = rand();
- cout << "Insert:" << x << ":" << i << endl;
- t1.Insert(make_pair(x, i));
- }
- cout << "IsBalance:" << t1.IsBalance() << endl;
- }
-
-
- int main()
- {
- TestRBTree2();
- cout << endl;
- TestRBTree1();
- return 0;
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。