红黑树

来源:互联网 发布:java将对象转换为json 编辑:程序博客网 时间:2024/06/11 03:26

一、概念

红黑树是一棵二叉搜索树,它在每个结点上增加了一个存储位来表示结

点的颜色,可以是red或者black,通过对任何一条从根节点到叶子结点上

的简单路径来约束,红黑树保证最长路径不超过最短路径的两倍,因而近视

平衡。

二、性质

1. 每个结点不是红色就是黑色

2. 根节点是黑色的

3. 如果一个根节点是红色的,则它的两个叶子结点是黑色的(没有两个连续

的红色结点)

4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相

同数目的黑色结点(每条路径上黑色结点的数量相等)

5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

思考:

为什么满足上面的颜色约束性质,红黑树能保证最长路径不超过最短路径的两

倍?

三、插入实现

注意:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点

【情况一】

cur为红,p为红,g为黑,u存在且为红

则将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。

 

【情况二】

cur为红,p为红,g为黑,u不存在/u为黑

pg的左孩子,curp的左孩子,则进行右单旋转;相反,pg的右孩子,cur

p的右孩子,则进行左单旋转

pg变色--p变黑,g变红


【情况三】

cur为红,p为红,g为黑,u不存在/u为黑

pg的左孩子,curp的右孩子,则针对p做左单旋转;相

反,pg的右孩子,curp的左孩子,则针对p做右单旋转

则转换成了情况2



四、源码实现:

RBTree.h

#pragma once#include<iostream>#include<stdio.h>#include<stdlib.h>using namespace std;enum Color{RED,BLACK};template<class K, class V>struct RBTreeNode{RBTreeNode(const K& key, const V& value, Color color = RED):_value(value), _key(key), _pLeft(NULL), _pRight(NULL), _pParent(NULL), _color(color){}V _value;K _key;RBTreeNode<K, V>* _pLeft;RBTreeNode<K, V>* _pRight;RBTreeNode<K, V>* _pParent;Color _color;             //节点的颜色};template<class K, class V>class RBTree{typedef RBTreeNode<K, V> Node;public:RBTree():_pHead(NULL){_pHead = new Node(0, 0);_pHead->_pLeft = _pHead;_pHead->_pRight = _pHead;}Node *GetMaxNode(){Node* pCur = GetRoot();while (pCur->_pRight)pCur = pCur->_pRight;return pCur;}Node *GetMinNode(){Node* pCur = GetRoot();while (pCur->_pLeft)pCur = pCur->_pLeft;return pCur;}bool Insert(const K& key, const V& value){Node*& pRoot = GetRoot();if (pRoot == NULL)      // 当一个节点也没有时{pRoot = new Node(key, value);pRoot->_color = BLACK;pRoot->_pParent = _pHead;return true;}Node* pCur = pRoot;Node* pParent = NULL;while (pCur){if (key < pCur->_key){pParent = pCur;pCur = pCur->_pLeft;}else if (key == pCur->_key)//若已存在,返回false{return false;}else{pParent = pCur;pCur = pCur->_pRight;}}pCur = new Node(key, value);if (key < pParent->_key){pParent->_pLeft = pCur;pCur->_pParent = pParent;}else{pParent->_pRight = pCur;pCur->_pParent = pParent;}//调整颜色while (pCur != pRoot && pParent->_color == RED){Node* garndFather = pParent->_pParent;Node* uncle = NULL;if (pParent == garndFather->_pRight){uncle = garndFather->_pLeft;}elseuncle = garndFather->_pRight;if (uncle != NULL&&uncle->_color == RED){pParent->_color = BLACK;uncle->_color = BLACK;garndFather->_color = RED;}else   //uncle不存在或uncle为黑{if (pParent == garndFather->_pLeft) //父亲是爷爷的左孩子{if (pCur = pParent->_pRight){RotateLeft(pParent);swap(pParent, pCur);}if (pCur = pParent->_pLeft){RotateRight(garndFather);pParent->_color = BLACK;garndFather->_color = RED;}}else                //父亲是爷爷的右孩子{if (pCur = pParent->_pLeft){RotateRight(pParent);swap(pParent, pCur);}if (pCur = pParent->_pRight){RotateLeft(garndFather);pParent->_color = BLACK;garndFather->_color = RED;}}}pCur = garndFather;pParent = pCur->_pParent;}_pHead->_pLeft = GetMinNode();_pHead->_pRight = GetMaxNode();pRoot->_color = BLACK;return true;}void RotateLeft(Node* parent){Node* pparent = parent->_pParent;Node* subR = parent->_pRight;Node* subRL = subR->_pLeft;if (pparent == _pHead){Node*& pRoot = GetRoot();pRoot = subR;}else{if (parent == pparent->_pLeft){pparent->_pLeft = subR;}else{pparent->_pRight = subR;}}subR->_pParent = pparent;parent->_pParent = subR;parent->_pRight = subRL;if (subRL != NULL){subRL->_pParent = parent;}}void RotateRight(Node* parent){Node* subL = parent->_pLeft;Node* subLR = subL->_pRight;Node* pparent = parent->_pParent;if (pparent == _pHead){Node*& pRoot = GetRoot();pRoot = subL;}else{if (parent = pparent->_pLeft){pparent->_pLeft = subL;}else{pparent->_pRight = subL;}}subL->_pParent = pparent;subL->_pRight = parent;parent->_pParent = subL;parent->_pLeft = subLR;if (subLR != NULL){subLR->_pParent = parent;}}void InOrder(){Node*& pRoot = GetRoot();_InOrder(pRoot);}void _InOrder(Node* pRoot){if (pRoot){_InOrder(pRoot->_pLeft);cout << pRoot->_key << " ";_InOrder(pRoot->_pRight);}}bool CheckRBTree(){Node*& pRoot = GetRoot();if (pRoot == NULL){return true;}if (pRoot->_color == RED){return false;}//找到一条路径上黑色节点的个数size_t blackCount = 0;Node* pCur = pRoot;while (pCur){if (pCur->_color == BLACK){blackCount++;}pCur = pCur->_pLeft;}size_t k = 0;return _CheckRBTree(pRoot, blackCount, k);}//每一条路径上的黑色节点相同时才是红黑树bool _CheckRBTree(Node* pRoot, const size_t blackCount, size_t k)//k一定为值传递{if (pRoot == NULL){return true;}//当出现两个连续的红色节点的时候,可以确定不是红黑树if (pRoot->_pParent&&pRoot->_color == RED&&pRoot->_pParent->_color == RED){return false;}//若是黑节点,k++if (pRoot->_color == BLACK){k++;}//若是叶子节点,判断k和blackCount是否相等if (pRoot->_pLeft == NULL&&pRoot->_pRight == NULL){if (k != blackCount){return false;}}return _CheckRBTree(pRoot->_pLeft, blackCount, k);}private:Node* _pHead;  //红黑树加上一个头结点进行迭代器操作//(头结点的左孩子指向红黑树的最小值,右孩子指向最大值,parent域指向根节点)private:Node* & GetRoot(){return _pHead->_pParent;}};

RBTree.cpp

#include"RBTree.h"void Test(){int a[] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };RBTree<int, int> bt;for (size_t idx = 0; idx < sizeof(a) / sizeof(a[0]); ++idx){bt.Insert(a[idx], a[idx]);}bt.InOrder();cout << endl;cout << bt.CheckRBTree() << endl;}int main(){Test();system("pause");return 0;}

五、红黑树和AVL树的比较

红黑树和AVL树都是高效的平衡二叉树,增删查改的时间复杂度都是

O(lg(N))

红黑树的不追求完全平衡,保证最长路径不超过最短路径的2倍,相对而

言,降低了旋转的要求,所以性能跟AVL树差不多,但是红黑树实现更简

单,所以实际运用中红黑树更多。

原创粉丝点击