RBTree——红黑树
来源:互联网 发布:佳能照片打印机软件 编辑:程序博客网 时间:2024/05/29 04:13
红黑树:
红黑树是一棵二叉搜索树,它在每个节点上增加了一个存储位来表示结点的颜色,红色或黑色(Red或Black)
通过对任何一条从根到叶子简单路径上的颜色来约束,红黑树保证最长路径不超过最短路径的两倍,从而达到近似平衡。
红黑树必须满足的性质:
1,每个节点不是红色就是黑色。
2,根节点必须为黑色。
3,如果一个节点是红色,则它的两个子节点是黑色
(即不能有两个连续的红色节点)。
4,对每个节点,从该节点到其所有后代的叶子节点的简单路径上,均包含相同数目的黑色节点。
5,每个叶子节点都是黑色(这里的叶子节点指NIL结点(空结点))(如果是空结点默认为黑色)。
我们可以先来思考一个简单的问题:
为什么红黑树加上了上面的颜色约束性质,它可以保证最长的路径不超过最短路径的两倍?
我们想一下最短路径应该是全黑,最长路径应该是红黑红黑相间。这么看来,它就可以保证最长路径不超过最短路径的两倍。
学完AVL树,接触红黑树时,它们是非常相似的,都会插入删除之后调节平衡,AVL树通过平衡因子调节平衡,红黑树通过颜色约束平衡,我们把AVL树称为高度平衡的二叉搜索树,而红黑树是近似平衡的二叉搜索树
所以在插入,删除上,AVL树旋转的次数比红黑树多,所以红黑树的插入,删除效率更高。
在应用中,红黑树应用更为广泛,在STL中,set,map,multiset,multimap的底层实现都是通过红黑树来完成的
红黑树的节点结构:
因为我们用颜色约束平衡,所以我们创建一个枚举类型来保存结点的颜色
代码实现
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 _col; RBTreeNode(const K& key, const V& value) :_left(NULL) , _right(NULL) , _parent(NULL) , _key(key) , _value(value) , _col(RED) {}};
插入:
我们将红黑树的插入分为五种情况:
第一种:
第二种:
情况二具体情况:1,u不存在
如上图:如果u不存在,那么,a,b,c,d,e也一定都不存在
u存在为黑:
如情况二的图:如果u存在为黑,那么,d,e不一定存在,是下图变上去的:
第三种:
第四种:第四种情况与第二种情况是接近的,不同的是:p是g的右孩子,cur是p的右孩子。我们要进行的是左单旋。
第五种:第五种情况与第三种情况是接近的,不同的是:p是g的右孩子,cur是p的左孩子,要先进行右单旋,然后变为第四种情况。
最后两种就不用图演示了,相信看完前三种情况,最后两种也一定可以清除。
代码实现:
bool Insert(const K& key,const V& value) { if (_root == NULL) { _root = new Node(key,value); _root->_col = BLACK; return true; } Node* parent = NULL; Node* cur = _root; 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->_right = cur; cur->_parent = parent; } else { parent->_left = cur; cur->_parent = parent; } while (parent&&parent->_col == RED) { Node* grandparent = parent->_parent; if (parent == grandparent->_left) { Node* uncle = grandparent->_right; if (uncle&&uncle->_col == RED) { parent->_col = BLACK; uncle->_col = BLACK; grandparent->_col = RED; cur = grandparent; parent = cur->_parent; } else //uncle不存在,或uncle为黑色 { if (cur == parent->_right) { RotateL(parent); swap(parent,cur); } RotateR(grandparent); parent->_col = BLACK; grandparent->_col = RED; break; } } else//parent == grandparent->_right { Node* uncle = grandparent->_left; if (uncle&&uncle->_col == RED) { parent->_col = BLACK; uncle->_col = BLACK; grandparent->_col = RED; } else//uncle不存在或者为黑色 { if (cur == parent->_left) { RotateR(parent); swap(parent, cur); } RotateL(grandparent); parent->_col = BLACK; grandparent->_col = RED; break; } } } _root->_col = BLACK; return true; }
左单旋右单旋:这个在AVL树中讲过,这里只给出代码啦
void RotateL(Node* parent) { Node* subR = parent->_right; Node* subRL = subR->_left; parent->_right = subRL; if (subRL) { subRL->_parent = parent; } subR->_left = parent; Node* parentparent = parent->_parent; parent->_parent = subR; if (parentparent==NULL) { _root = subR; _root->_parent = NULL;//不置空,会死循环 } else { if (parent == parentparent->_left) { parentparent->_left = subR; subR->_parent = parentparent; } else { parentparent->_right = subR; subR->_parent = parentparent; } } } void RotateR(Node* parent) { Node* subL = parent->_left; Node* subLR = subL->_right; parent->_left = subLR; if (subLR) { subLR->_parent = parent; } subL->_right = parent; Node* parentparent = parent->_parent; parent->_parent = subL; if (parentparent == NULL) { _root = subL; _root->_parent = NULL; } else { if (parent == parentparent->_left) { parentparent->_left = subL; subL->_parent = parentparent; } else { parentparent->_right = subL; subL->_parent = parentparent; } } }
判断是否为红黑树:
满足红黑树的性质
满足黑节点个数相同的方法:
根节点固定是黑色,为1是固定的,每个孩子都依赖于父亲,当前结点是黑色,那么黑色节点的数量是父亲数量+1,如果当前节点为红色,那么黑色节点数量是父亲数量本身,每个节点没必要都记下来,可以选择一个参数,选择参数方法:
1,当左右都为空时求出来的的黑色节点数量都push到容器中,最后该容器中数据如果一样为红黑树
2,先求出来最左(或右)黑色节点的个数,其他的路径的黑色结点与他相比,若相同为红黑树
下面代码用的是第二种方法:
bool IsBalance() { if (_root == NULL) { return true; } if (_root&&_root->_col==RED) { return false; } int BlackNum = 0; Node* left = _root; while (left) { if (left->_col == BLACK) { ++BlackNum; } left = left->_left; } int num = 0; return _IsBalance(_root, num, BlackNum); } bool _IsBalance(Node* root, int num, const int blackNum) { if (root == NULL) { return true; } if (root->_col == RED&&root->_parent->_col == RED) { cout<<"存在连续的红节点"<<root->_key<<endl; return false; } if (root->_col == BLACK) { ++num; } // num 是根节点到当前节点黑色节点的数量 if (root->_left == NULL && root->_right == NULL) { if (num != blackNum) { //cout<<"黑色节点的数量不相等"<<root->_key<<endl; return false; } else { return true; } } return _IsBalance(root->_left, num, blackNum) && _IsBalance(root->_right, num, blackNum); }
完整代码:
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 _col; RBTreeNode(const K& key, const V& value) :_left(NULL) , _right(NULL) , _parent(NULL) , _key(key) , _value(value) , _col(RED) {}};template<class K,class V>class RBTree{ typedef RBTreeNode<K,V> Node;public: RBTree() :_root(NULL) {} bool Insert(const K& key,const V& value) { if (_root == NULL) { _root = new Node(key,value); _root->_col = BLACK; return true; } Node* parent = NULL; Node* cur = _root; 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->_right = cur; cur->_parent = parent; } else { parent->_left = cur; cur->_parent = parent; } while (parent&&parent->_col == RED) { Node* grandparent = parent->_parent; if (parent == grandparent->_left) { Node* uncle = grandparent->_right; if (uncle&&uncle->_col == RED) { parent->_col = BLACK; uncle->_col = BLACK; grandparent->_col = RED; cur = grandparent; parent = cur->_parent; } else //uncle不存在,或uncle为黑色 { if (cur == parent->_right) { RotateL(parent); swap(parent,cur); } RotateR(grandparent); parent->_col = BLACK; grandparent->_col = RED; break; } } else//parent == grandparent->_right { Node* uncle = grandparent->_left; if (uncle&&uncle->_col == RED) { parent->_col = BLACK; uncle->_col = BLACK; grandparent->_col = RED; } else//uncle不存在或者为黑色 { if (cur == parent->_left) { RotateR(parent); swap(parent, cur); } RotateL(grandparent); parent->_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; if (subRL) { subRL->_parent = parent; } subR->_left = parent; Node* parentparent = parent->_parent; parent->_parent = subR; if (parentparent==NULL) { _root = subR; } else { if (parent == parentparent->_left) { parentparent->_left = subR; subR->_parent = parentparent; } else { parentparent->_right = subR; subR->_parent = parentparent; } } } void RotateR(Node* parent) { Node* subL = parent->_left; Node* subLR = subL->_right; parent->_left = subLR; if (subLR) { subLR->_parent = parent; } subL->_right = parent; Node* parentparent = parent->_parent; parent->_parent = subL; if (parentparent == NULL) { _root = subL; _root->_parent = NULL; } else { if (parent == parentparent->_left) { parentparent->_left = subL; subL->_parent = parentparent; } else { parentparent->_right = subL; subL->_parent = parentparent; } } } 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() { if (_root == NULL) { return true; } if (_root&&_root->_col==RED) { return false; } int BlackNum = 0; Node* left = _root; while (left) { if (left->_col == BLACK) { ++BlackNum; } left = left->_left; } int num = 0; return _IsBalance(_root, num, BlackNum); } bool _IsBalance(Node* root, int num, const int blackNum) { if (root == NULL) { return true; } if (root->_col == RED&&root->_parent->_col == RED) { cout<<"存在连续的红节点"<<root->_key<<endl; return false; } if (root->_col == BLACK) { ++num; } // num 是根节点到当前节点黑色节点的数量 if (root->_left == NULL && root->_right == NULL) { if (num != blackNum) { //cout<<"黑色节点的数量不相等"<<root->_key<<endl; return false; } else { return true; } } return _IsBalance(root->_left, num, blackNum) && _IsBalance(root->_right, num, blackNum); }private: Node* _root;};void TestRBTree(){ RBTree<int, int> t; int a[] = {16, 3, 7, 11, 9, 26, 18, 14, 15}; //int a[] = {4, 2, 6, 1, 3, 5, 15, 7, 16, 14}; for (size_t i = 0; i < sizeof(a)/sizeof(a[0]); ++i) { t.Insert(a[i], i); } t.InOrder(); cout<<"IsBalance?"<<t.IsBalance()<<endl;}
- RBTree——红黑树
- 二叉搜索树—RBTree(红黑树)
- 红黑树-RBTree
- RBTree红黑树
- RBTree----红黑树
- RBTree(红黑树)
- 红黑树--RBTree
- 红黑树【RBTree】
- 红黑树(RBtree)
- RBTree-红黑树的实现
- 【c++/数据结构】红黑树-RBTree
- 数据结构-红黑树(RBTree)
- 【数据结构】中的红黑树-RBTree
- 红黑树(RBTree)
- RBTree(红黑树)
- 6.Nginx红黑树rbtree
- RBTree
- RBTree
- PAT甲级 1033. To Fill or Not to Fill (25)
- C++结构中的位字段和共用体
- bmfont的设置
- WebRTC代码目录结构
- 【装载】你有一大堆货物和两条船!
- RBTree——红黑树
- 二维数组动态分配内存
- UE4引擎架构
- 剑指offer 查找二位数组
- 开启分享经济的新时代!消费者也能成为“资本家”
- 帧同步和状态同步
- Useful tips to scrapy web pages with Python(Request)
- 狗宝宝取名大全2018款之提前为宝宝取名好吗
- window7下手动启动MySQL-server