一
红黑树:首先红黑树是一颗搜索二叉树,树中的每个结点不是红色就是黑色。它的特征如下:
1.根节点是黑色
2.每个结点不是黑色就是红色
3.不能有两个连续的红结点
4.每条路径上黑色结点数量相同
二
为什么要有红黑树?
最开始我们学习了搜索二叉树,但是搜索二叉树有可能出现单链的情况,之后我们又引入了AVL树,AVL树是一种高度平衡的二叉搜索树。能够满足增加,删除,查找都是o(lg N)的时间复杂度,为什莫还要引入红黑树呢?
这时由于AVL树是高度平衡二叉搜索树,维持一颗AVL树的代价相比红黑树要大很多,由于它的高度平衡,使得几乎每次插入或者删除都要调整树。而红黑树是一颗近似平衡的二叉搜索树,它满足最长路径不超过最短路径的两倍,易于维护。而且红黑树效率最短路径lgN,最长路径2LgN
三
思考为什莫红黑树满足它的性质,就能保证最长路径不超过最短路径的两倍。。。最短,全黑,最长,每个黑的中间加个红
最多也就二倍,因此保证了最长路径不超过最短路径的两倍
四 插入
一般默认插入的结点是红的(如果黑的,每条路径上都要增加)
1.如果要插入的结点是根节点,则直接插入,并将根节点染为黑色
2.如果插入位置父亲是黑色,直接插入
3.如果要插入位置的父亲是红色的,这时如果再插入一个红色结点,就会出现两个连续的红色结点。
假如要插入的结点是cur,它的父亲是parent,它的父亲的兄弟是uncle,它的祖父是grandfather.
分为两种情况1.叔叔存在且为红
2.叔叔不存在,或者叔叔为黑
#pragma once #include<iostream> using namespace std; 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 _cor; RBTreeNode (const K&key,const V&value ) :_left ( NULL ) , _right ( NULL ) , _parent (NULL ) , _key (key ) , _value (value) , _cor (RED ) {} }; template<class K,class V> class RBTree {public: typedef RBTreeNode<K, V> Node; RBTree ( ) :_Root ( NULL ) {} bool Insert ( const K& key, const V& value ) { if ( _Root == NULL ) { _Root = new Node ( key, value ); _Root->_cor = 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; } //检查 //1.parent为黑 //2.parent为红,叔叔存在且为红 //3.parent为红,叔叔不存在,或者叔叔存在且为黑 while (parent&& parent->_cor == RED ) { Node* Grandfather = parent->_parent; if ( parent == Grandfather->_left ) { Node* uncle = Grandfather->_right; if( uncle&&uncle->_cor == RED)//叔叔存在且为红色 { uncle->_cor = parent->_cor = BLACK; Grandfather->_cor = RED;//继续往上调 cur = Grandfather; parent = cur->_parent; } else//叔叔不存在或者叔叔等于黑 { //双旋 if ( cur == parent->_right ) { RotateL (parent ); swap(parent, cur); } //单旋 RotateR ( Grandfather ); parent->_cor = BLACK; Grandfather->_cor = RED; } } else { Node* uncle = Grandfather->_left; if ( uncle&&uncle->_cor == RED )//叔叔存在且为红 { parent->_cor = uncle->_cor = BLACK; Grandfather->_cor = RED;//继续向上调整 cur = Grandfather; parent = cur->_parent; } else//叔叔不存在,或者叔叔存在且为黑 { if ( cur == parent->_left ) { RotateR ( parent ); swap(parent, cur); } RotateL ( Grandfather ); Grandfather->_cor = RED; parent->_cor = BLACK; } } } _Root->_cor = BLACK; return true; } 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; _Root->_parent = NULL; } else { if ( ppNode->_left == parent ) ppNode->_left = subL; else ppNode->_right = subL; subL->_parent = ppNode; } } 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; _Root->_parent = NULL; } else if ( ppNode->_left == parent ) { ppNode->_left = subR; } else { ppNode->_right = subR; } subR->_parent == ppNode; } 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 ( )//判断是否平衡 //首先我们会想到拿高度判断,最长不超多最短二倍 但是颜色可能不符合,因此不能仅仅拿高度来判断 //判断:1.根是黑的 2.没有连续红色结点 (递归遍历) 3.每条路径上黑色结点数目相等 { if ( _Root->_cor == RED ) { return false; } int k = 0; int blacknum = 0; Node* cur = _Root; while ( cur ) { if ( cur->_cor == BLACK ) { k++; } cur = cur->_left; } return _IsBalance ( _Root,k,blacknum ); } private://注意此处blacknum不能给引用 bool _IsBalance ( Node* cur, const int& k,int blacknum )//想想我们如何判断每个路径上黑色结点数量相同 有的人会说用容器存 空间复杂度 即为最后一层结点数 2^(log 2 N)-1 也就是O(N)显然是不行的 { //因此我们不妨先把最左边,或者最右边一条路径上黑节点算出来,然后和其他路径上对比,如果有不同,说明每条路径上黑色结点树不同 if ( cur == NULL ) { if ( blacknum != k ) { cout << "黑节点数目不想等" << " " << endl; return false; } else { return true; } } Node* parent = cur->_parent; if (( cur->_cor == RED)&&(parent->_cor == RED ))//注意,一般我们会想如何判断没有连续红节点,回想着判断它的左右孩子是否为红。这样还要考虑左孩子,右孩子 { //此处 我们不妨逆着来想,反正每个结点会被遍历到,判断它的父亲是否为红。 cout << "存在连续的红色结点" << cur->_key << endl; return false; } if ( cur->_cor == BLACK ) { blacknum++; } return _IsBalance ( cur->_left, k, blacknum ) && _IsBalance ( cur->_right, k, blacknum ); } private: Node* _Root; }; void Test ( ) { int arr[] = {16,3,7,11,9,26,18,14}; RBTree<int, int>t1; for ( int i = 0; i < sizeof(arr) / sizeof (arr[0]); i++ ) { t1.Insert ( arr[i],i); cout <<arr[i]<<" "<<"Isbalance?"<< t1.Isbalance ( ) << endl; } t1.Inorder (); cout<<t1.Isbalance ( )<<endl; }