高效的平衡搜索树——红黑树
2016-07-24 23:53
399 查看
红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3 每个叶节点是黑色的。
性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
红黑树的插入分为以下三种情况
第一种情况:
cur为红节点,parent为红节点,grandfather为黑节点,uncle存在且为红
变换:将parent改为黑节点,grandfather改为红节点,然后把grandfather当成cur,并且向上调整
第二种情况:
cur为红节点,parent为红节点,grandfather为黑节点,uncle不存在/uncle为红节点
变换:(1)parent为grandfather的左孩子,cur为parent的左孩子,则进行右单旋转
(2)parent为grandfather的右孩子,cur为parent的右孩子,则进行左单旋转
最后,将parent变为黑节点,将grandfather变为红节点
第三种情况:
cur为红节点,parent为红节点,grandfather为黑节点,uncle不存在/uncle为黑节点
变换:(1)parent为grandfather的左孩子,cur为parent的右孩子,则针对parent进行左单旋转
(2)parent为grandfather的右孩子,cur为parent的左孩子,则针对parent进行右单旋转
此时情况变成了情况2,可以按照情况2的办法来处理
变色后出现的情况讨论
关于红黑树中用到的旋转图解
下面是代码分析:
"RBTree.h"
"test.cpp"
性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3 每个叶节点是黑色的。
性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
红黑树的插入分为以下三种情况
第一种情况:
cur为红节点,parent为红节点,grandfather为黑节点,uncle存在且为红
变换:将parent改为黑节点,grandfather改为红节点,然后把grandfather当成cur,并且向上调整
第二种情况:
cur为红节点,parent为红节点,grandfather为黑节点,uncle不存在/uncle为红节点
变换:(1)parent为grandfather的左孩子,cur为parent的左孩子,则进行右单旋转
(2)parent为grandfather的右孩子,cur为parent的右孩子,则进行左单旋转
最后,将parent变为黑节点,将grandfather变为红节点
第三种情况:
cur为红节点,parent为红节点,grandfather为黑节点,uncle不存在/uncle为黑节点
变换:(1)parent为grandfather的左孩子,cur为parent的右孩子,则针对parent进行左单旋转
(2)parent为grandfather的右孩子,cur为parent的左孩子,则针对parent进行右单旋转
此时情况变成了情况2,可以按照情况2的办法来处理
变色后出现的情况讨论
关于红黑树中用到的旋转图解
下面是代码分析:
"RBTree.h"
#pragma once enum Colour { RED, BLACK, }; template<class K,class V> class RBTreeNode { public: RBTreeNode(const K& key,const V& value) :_left(NULL) ,_right(NULL) ,_parent(NULL) ,_key(key) ,_value(value) ,_col(RED) {} public: //定义一个三叉链 RBTreeNode<K,V>* _left;//左孩子 RBTreeNode<K,V>* _right;//右孩子 RBTreeNode<K,V>* _parent;//父亲 K _key; V _value; Colour _col; }; 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* 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->_key < key { parent->_right = cur; cur->_parent = parent; } while ((cur != _root) && (parent->_col == RED))//保证了grandfher的存在 { Node* grandfather = parent->_parent; if (grandfather->_left == parent) { Node* uncle = grandfather->_right; //情况1 见下图 if ((uncle) && (uncle->_col == RED)) { parent->_col = uncle->_col = BLACK; grandfather->_col = RED; cur = grandfather; parent = cur->_parent; } else { //情况3 见下图 if (cur == parent->_right) { _RotateL(parent); swap(parent,cur); } //情况2 见下图 parent->_col = BLACK; grandfather->_col = RED; _RotateR(grandfather); break; } } else //grandfather->_right == parent { Node* uncle = parent->_left; //情况1 见下图 if ((uncle) && (uncle->_col == RED)) { parent->_col = uncle->_col = BLACK; grandfather->_col = RED; cur = grandfather; parent = cur->_parent; } else { //情况3 见下图 if (parent->_left == cur) { _RotateR(parent); swap(parent,cur); } //情况3 parent->_col = BLACK; grandfather->_col = RED; _RotateL(grandfather); break; } } _root->_col = BLACK;//记得每次调整完成后,整课二叉树的根节点的颜色要调成黑色 //此时才满足二叉树的性质 } } void InOrder() { _InOrder(_root); cout<<endl; } bool IsBlance() { //满足一棵红黑树的性质 //1.根节点是黑色的 //2.没有连续的红节点 //3、每条路径上的黑色节点数目相同 //4、最长路径不超过最短路径的两倍 if (_root == NULL) { //空数也满足红黑树的性质 return true; } if (_root->_col == RED) { //违背了性质的第一条 return false; } int k = 0; Node* cur = _root; while (cur) { if (cur->_col == BLACK) { k++; } //求出任意一条路径的黑色节点数量 cur = cur->_left; } int count = 0; return _IsBlance(_root,k,count); } private: bool _IsBlance(Node* root,const int k,int count) { if (root == NULL) { //空树满足红黑树的性质 return true; } return _IsBlance(root->_left,k,count) && _IsBlance(root->_right,k,count); if ((root->_col == RED) && (root->_parent->_col == RED)) { cout<<root->_key<<" 有连续的红节点"<<endl; return false; } if (root->_col == BLACK) { ++count; } if ((root->_left == NULL) && (root->_right == NULL) && (k != count)) { cout<<root->_key<<" 路径上的黑色节点数目不相同"<<endl; return false; } } 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; subR->_parent = NULL; } else //ppNode != NULL { if (ppNode->_left == parent) { ppNode->_left = subR; } else //ppNode->_right == parent { ppNode->_right = subR; } subR->_parent = ppNode; } } 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; subL->_parent = NULL; } else { if (ppNode->_left == parent) { ppNode->_left = subL; } else //ppNode->_right == parent { ppNode->_right = subL; } subL->_parent = ppNode; } } void _InOrder(Node* root) { if (root == NULL) { return; } _InOrder(root->_left); cout<<root->_key<<" "; _InOrder(root->_right); } private: Node* _root; };
"test.cpp"
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; #include "RBTree.h" void Test() { RBTree<int,int> rbt; //int arr[] = {16,3,7,11,9,26,18,14,15}; int arr[] = {48,12,56,32,99,11,10,78,22}; int size = sizeof(arr)/sizeof(arr[0]); for (int i = 0;i < size;i++) { rbt.Insert(arr[i],i); cout<<"IsBlance? "<<rbt.IsBlance()<<endl; } rbt.InOrder(); cout<<"IsBlance? "<<rbt.IsBlance()<<endl; } int main() { Test(); system("pause"); return 0; }
相关文章推荐
- ajax编程
- Linux下更改目录及其下的子目录和文件的访问权限
- struts配置文件中结果类型小结
- POJ2606&1118 同直线最多点数
- 使用httpd-2.2和httpd-2.4实现指定httpd服务
- 计算机网络——物理层(3)
- Android设置ViewPager不能左右滑动
- TCP协议
- Android-5.1-bootchart
- LeetCode进阶之路(Merge Two Sorted Lists)
- Android获取系统当前时间
- css伪类选择器详细解析及案例使用-----伪类选择器(2)
- Linux中安装和使用rz、sz命令
- 生信招聘
- MySQL数据安装卸载解决方案以及基本增删改查
- Linux shell script学习
- lightoj1079【背包】
- shell script input and out put functuo
- 复制表数据、表结构;临时表创建
- 报错信息为:java.lang.IllegalStateException: The specified child already has a parent.