红黑树

来源:互联网 发布:许朝军 知乎 编辑:程序博客网 时间:2024/05/22 10:40

红黑树介绍:

红黑树是一棵二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,可以是Red或Black。通过对任何一条从根到叶子简单路径上的颜色来约束,红黑树保证最长路径不超过最短路径的两倍,因而近似于平衡。
红黑树和我们以前学过的AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。红黑树和AVL树的区别在于它使用颜色来标识结点的高度,它所追求的是局部平衡而不是AVL树中的非常严格的平衡。
红黑树是满足下面红黑性质的二叉搜索树:
  1. 每个节点,不是红色就是黑色的
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的两个子节点是黑色的(没有连续的红节点)
  4. 对每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。(每条路径的黑色节点的数量相等
  5. 每个叶子节点都是黑色的(这里的叶子节点是指的NIL节点(空节点))
红黑树包括插入、删除、查找等操作。
插入: 根据性质4,新增节点必须为红色;根据性质3,新增节点的父节点必须为黑色。
1、若该树为空树,直接插入根结点的位置,违反性质2,把节点颜色有红改为黑即可。
2、插入节点cur的父节点parent为黑色,不违反任何性质,无需做任何修改
3、插入节点cur为红,parent为红,grandfather为黑,uncle存在且为红,这里不论parent是grandfather的左孩子,还是右孩子,不论cur是parent的左孩子,还是右孩子则将parent,uncle改为黑,grandfather改为红,然后把grandfather当成cur,继续向上调整
ps:cur为当前节点,parent为父节点,grandfather为祖父节点,uncle为叔叔节点

 解析:cur、parent都为红,违反性质3;若把parent改为黑,符合性质3,但是左边少了一个黑节点,违反性质4;所以我们把grandfather、cur都改为相反色,这样一来通过grandfather的路径的黑节点数目没变,即符合3、4,若grandfather的父节点又是红的就又违反了3,所以经过上边操作后未结束,需把grandfather作为cur继续向上检索。
  4、cur为红,parent为红,grandfather为黑,uncle不存在/uncle为黑,parent为grandfather的左孩子,cur为parent的左孩子,则进行右单旋转;相反,parent为grandfather的右孩子,cur为parent的右孩子,则进行左单旋转,parent变黑,grandfather变红

5、cur为红,parent为红,grandfather为黑,uncle不存在/uncle为黑parent为grandfather的左孩子,cur为parent的右孩子,则针对parent做左单旋转;相反,parent为grandfather的右孩子,cur为parent的左孩子,则针对parent做右单旋转,则转换成了情况4

红黑树左单旋转和右单旋转同AVL树左单旋转和右单旋转一样,详见http://blog.csdn.net/wanglelelihuanhuan/article/details/51863275

RBTree.h
#pragma onceenum Color{RED,BLACK,};template<class K, class V>struct RBTreeNode{K _key;V _value;RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;Color _color;RBTreeNode<K, V>(const K& key, const V& value): _key(key), _value(value), _left(NULL), _right(NULL), _parent(NULL), _color(RED){}};template<class K, class V>class RBTree{typedef RBTreeNode<K, V> Node;public:RBTree():_root(NULL){}public:bool Insert(const K& key, const V& value){if (_root == NULL){_root = new Node(key, value);_root->_color = 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->_right = cur;cur->_parent = parent;}//再调颜色while (cur != _root && parent->_color == RED){Node* grandfather = parent->_parent;if (grandfather->_left == parent){//第一种情况,uncle存在且为红,进行变色处理Node* uncle = grandfather->_right;if (uncle && uncle->_color == RED){parent->_color = uncle->_color = BLACK;grandfather->_color = RED;//然后把grandfather当成cur,继续向上调整。cur = grandfather;parent = cur->_parent;}else  // uncle不存在/uncle存在为黑{//第三种情况,左右双旋   '<'-->'/'-->'/\'if (cur == parent->_right){RotateL(parent);swap(parent, cur);}grandfather->_color = RED;parent->_color = BLACK;RotateR(grandfather);break;}}else //grandfather->_right == parent{Node* uncle = grandfather->_left;if (uncle && uncle->_color == RED){parent->_color = uncle->_color = BLACK;grandfather->_color = RED;cur = grandfather;parent = cur->_parent;}else{//右左双旋      '>'-->'\'-->'/\'if (cur == parent->_left){RotateR(parent);swap(parent, cur);}grandfather->_color = RED;parent->_color = BLACK;RotateL(grandfather);break;}}}_root->_color = BLACK;return  true;}void InOrder(){if (_root == NULL)return;_InOrder(_root);cout << endl;}bool IsBalance(){if (_root == NULL || (_root && _root->_color == RED))return false;//统计最左路径中黑色节点个数int k = 0;Node* cur = _root;while (cur){if (cur->_color == BLACK){++k;}cur = cur->_left;}int count = 0;return _IsBalance(_root, k, count);}public:void _InOrder(Node* root){if (root == NULL)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}bool _IsBalance(Node* root, const int k, int count){if (root->_color == RED && root->_parent->_color == RED){return false;}if (root->_color == BLACK){++count;}if (root->_left == NULL&&root->_right == NULL){if (k != count){cout << "黑色节点个数不相等" << root->_key << endl;return false;}else{cout << "平衡" << endl;return true;}}return _IsBalance(root->_left, k, count);return _IsBalance(root->_right, k, count);}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;parent->_parent = subR;if (ppNode == NULL){_root = subR;subR->_parent = NULL;}else{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;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;}protected:Node* _root;};void TestInsert(){int arr[] = { 16, 3, 7 };RBTree<int, int> rb;for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i){rb.Insert(arr[i], i);cout << arr[i] << endl;cout << "IsBalance  " << rb.IsBalance() << endl;}cout << "IsBalance  " << rb.IsBalance() << endl;rb.InOrder();}

Test.cpp
#include<iostream>using namespace std;#include"RBTree.h"int main(){TestInsert();return 0;}


红黑树和AVL树的比较

红黑树和AVL树都是高效的平衡二叉树,增删查改的时间复杂度都是O(lg(N))
红黑树的不追求完全平衡,保证最长路径不超过最短路径的2倍,相对而言,降低了旋转的要求,所以性能跟AVL树差不多,但是红黑树实现更简单,所以实际运用中红黑树更多。

0 0
原创粉丝点击