平衡二叉搜索树——红黑树
来源:互联网 发布:河师大教务网络系统 编辑:程序博客网 时间:2024/06/09 03:54
1.红黑树的简介
红黑树是一棵二叉搜索树,它在每个节点上增加了一个存储位_color来表示节点的颜色,可以是Red或Black。通过对任何一条从根到叶子简单
路径上的颜色来约束,红黑树保证最长路径不超过最短路径的两倍,因而近似于平衡。红黑树没有达到AVL树的高度平衡,换句话说,它的高度,并没有AVL树那么高的要求,但他的应用却更加的广泛,实践中是相当高效的,他可以在O(log2 n)的时间内做查找、插入、删除操作。在C++ STL中,set、multiset、map、multimap等都应用到的红黑树的变体。
2.红黑树的性质
(1)每个节点,不是红色就是黑色的
(2) 根节点是黑色的
(3) 如果一个节点是红色的,则它的两个子节点是黑色的
(4) 对每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。
(5)每个叶子节点都是黑色的(这里的叶子节点是指的NIL节点(空节点))
3.节点的定义
enum Color{ RED, BLACK};//三叉链template<typename K,typename V>struct RBTreeNode{ RBTreeNode<K, V>* _left; RBTreeNode<K, V>* _right; RBTreeNode<K, V>* _parent; K _key; V _value; int _color; RBTreeNode(const K& key, const V& value) :_left(NULL) , _right(NULL) , _parent(NULL) , _key(key) , _value(value) , _color(RED) {}};
有了AVL树的经验,红黑树旋转的时候并不是调节平衡因子,而是进行颜色。
要知道新插入的结点一定是红色,否则不能满足性质4.
插入操作:
1.树为空直接创建根节点,根节点设置为黑色
2.树不为空,就要分情况讨论了。
1>第一种情况
cur为红,p为红,g为黑,u存在且为红
则将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。
2>第二种情况
cur为红,p为红,g为黑,u不存在/u为黑
p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,p为g的右孩子,cur为p的右孩子,则进行左单旋转
p、g变色–p变黑,g变红(如果叔叔存在,cur为调整上来的节点,若叔叔不存在,cur为新插入的结点)
3>第三种情况
cur为红,p为红,g为黑,u不存在/u为黑
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;相反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转
则转换成了情况2,但要注意的是第一次旋转之后,cur与parent的位置
下面给出插入操作的代码:同样也是先找到插入位置(二叉搜索树的插入)
bool Insert(const K& key, const V& value) { if (_root == NULL) { _root = new Node(key, value); _root->_color = BLACK; return true; } else { 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->_left = cur; cur->_parent = parent; } else if (parent->_key < key) { parent->_right = cur; cur->_parent = parent; } while (parent&&parent->_color == RED) { Node* grandfather = parent->_parent; if (parent==grandfather->_left) { Node* uncle = grandfather->_right; //叔叔存在且为红 if (uncle&&uncle->_color == RED) { parent->_color = BLACK; uncle->_color = BLACK; grandfather->_color = RED; cur = grandfather; parent = cur->_parent; } else//叔叔不存在或者存在为黑色 { if (cur == parent->_right) {//2次旋转 RotateL(parent); swap(cur, parent); } RotateR(grandfather); parent->_color = BLACK; grandfather->_color = RED; } } else//parent==grandfather->_right { Node* uncle = grandfather->_left; //叔叔存在且为红 if (uncle&&uncle->_color == RED) { parent->_color = BLACK; uncle->_color = BLACK; grandfather->_color = RED; cur = grandfather; parent = cur->_parent; } else//叔叔不存在或者存在为黑色 { if (cur == parent->_left) {//双旋 RotateR(parent); swap(parent, cur); } RotateL(grandfather); parent->_color = BLACK; grandfather->_color = RED; } } } } _root->_color = 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* ppNode = parent->_parent;//subL->_parent = parent->_parent; parent->_parent = subR; if (ppNode == NULL) { _root = subR; subR->_parent = NULL; } else { if (parent == ppNode->_left) 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 (ppNode == NULL) { _root = subL; subL->_parent = NULL; } else { if (ppNode->_left == parent) { ppNode->_left = subL; } else { ppNode->_right = subL; } subL->_parent = ppNode; } }
插入操作结束,我们可以看出没最主要的是其uncle结点的作用。
我们最后来判断一下是否平衡
bool IsBalance() { if (_root == NULL) return true; if (_root&&_root->_color == RED) return false; int num = 0; int blacknum = 0; //求最左分支的黑结点的个数 Node* left = _root; while (left) { if (left->_color == BLACK) { ++blacknum; } left = left->_left; } return _IsBalance(_root, blacknum, num); } bool _IsBalance(Node* root, const int blacknum, int num) { if (root == NULL) { return true; } if (root->_color == RED&&root->_parent->_color == RED) { cout << "有两个连续的红结点" << endl; return false; } if (root->_color == BLACK) { ++num; } if (root->_left == NULL && root->_right == NULL && num!=blacknum ) { return false; } return _IsBalance(root->_left, blacknum, num) && _IsBalance(root->_right, blacknum, num); }
- 平衡二叉搜索树——红黑树
- 二叉搜索树—平衡二叉树
- 数据结构——二叉搜索平衡树
- 【数据结构】红黑树——自平衡二叉搜索树
- 平衡二叉搜索树
- 二叉平衡搜索树——AVL树
- 平衡二叉搜索树——AVL树
- 数据结构——平衡二叉搜索树(AvlTree)的实现
- AVL平衡二叉搜索树
- AVLTree----平衡二叉搜索树
- AVL平衡搜索二叉树
- AVL平衡二叉搜索树
- AVLTree二叉平衡搜索树
- 二叉搜索树与平衡二叉树
- 搜索二叉树和平衡二叉树
- 平衡二叉树——红黑树
- 数据结构—平衡二叉树
- 数据结构—平衡二叉树
- 剑指offer-面试题05-从尾到头打印链表
- Window内存管理方式:页式 段式 段页式
- javaweb学习总结(三十)——EL函数库
- 一个简单ajax
- javaweb学习总结(三十一)——国际化(i18n)
- 平衡二叉搜索树——红黑树
- javaweb学习总结(三十二)——JDBC学习入门
- xmlHttp和ajaxrequest
- 创建自定义拦截器(示例)----默然说话20140411备课笔记
- 删除相邻重复数据
- javaweb学习总结(三十三)——使用JDBC对数据库进行CRUD
- js 实现在离开页面时,对未保存的信息进行提醒
- javaweb学习总结(三十四)——使用JDBC处理MySQL大数据
- mysql颠覆实战课程