红黑树的实现

来源:互联网 发布:js小数点后最多写两位 编辑:程序博客网 时间:2024/05/29 14:58

红黑树(RBT)的定义它或者是一颗空树,或者是具有一下性质的二叉查找树:

1.节点非红即黑。

2.根节点是黑色。

3.所有NULL结点称为叶子节点,且认为颜色为黑

4.所有红节点的子节点都为黑色。

5.从任一节点到其叶子节点的所有路径上都包含相同数目的黑节点。

                                                             

上面的定义理解起来有点费解,所以我总结了以下三点,只要满足以下三点就可以是红黑树了。

                                       1.根节点必须是黑树

                               2.红树不能连续链接,黑树可以。

                               3.每条路径上黑树的个数必须是相同的。

插入操作(Insert)

由于性质的约束:插入点不能为黑节点,应插入红节点。因为你插入黑节点将破坏性质5,所以每次插入的点都是红结点,但是若他的父节点也为红,那就会破坏了性质4,所以要做一些“旋转”和一些节点的变色!另外为叙述方便,我们给要插入的节点分别定义如下:

             N(红色),父节点为P,祖父节点为G,叔节点为U

下边将一一列出所有插入时遇到的情况:

情况一:该树为空树,直接插入根结点的位置,违反性质1,把节点颜色有红改为黑即可

情况二:插入节点N的父节点P为黑色,不违反任何性质,无需做任何修改。

情况三:N为红,P为红,(祖节点一定存在,且为黑,下边同理)U也为红,这里不论P是G的左孩子,还是右孩子;不论N是P的左孩子,还是右孩子如下图所示:

操作:先把P和U变为黑色,然后G变为红色

                                                                                                                                                                      


情况四:N为红,P为红,U为黑,P为G的左孩子,N为P的左孩子(或者P为G的右孩子,N为P的左孩子;反正就是同向的)如下图所示:

操作:将P变黑,G变红,然后以p为轴右旋

                                                                                                                                                          

情况五:N为红,P为红,U为黑,P为G的左孩子,N为P的右孩子(或者P为G的右孩子,N为P的左孩子;反正两方向相反)。如下图所示:

 操作:首先以P为轴左旋,然后将p和N指向的地址交换,然后就转换为情况四                                    

                                                                                                                                                                                 


代码如下:


数据结构定义如下:

enum Colour{RED,BLACK,};template<class K, class V>struct RBTreeNode{// 链接结构RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;// Key/ValueK _key;V _value;// 颜色Colour _col;RBTreeNode(const K& key, const V& value, Colour col = RED):_left(NULL), _right(NULL), _parent(NULL), _col(col), _key(key), _value(value){}};
操作代码如下:

template<class K, class V>class RBTree{typedef RBTreeNode<K, V> Node;public:RBTree():_root(NULL){}bool Insert(const K& key, const V& value){//1.树为空if (_root == NULL){_root = new Node(key, value, BLACK);return true;}// 查找位置,插入节点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, RED);if (parent->_key < key){parent->_right = cur;cur->_parent = parent;}else{parent->_left = cur;cur->_parent = parent;}// 调整while (cur != _root && parent->_col == RED)   //这两个条件说明了cur一定存在parent 和 grandfather{Node* grandfather = parent->_parent;if (parent == grandfather->_left){Node* uncle = grandfather->_right;// case1if (uncle && uncle->_col == RED)   //uncle存在且uncle的颜色为红色{parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else // case2/case3    //uncle不存在 或 uncle存在但颜色为黑色{// case3->case2if (cur == parent->_right){_RotateL(parent);    //先左旋在交换swap(cur, parent);     //交换cur和parent的地址,此时cur指向parent的地址,parent指向cur的地址}grandfather->_col = RED;parent->_col = BLACK;_RotateR(grandfather);    //在右旋}}else   //parent == grandfather->_right{Node* uncle = grandfather->_left;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_left){_RotateR(parent);swap(cur, parent);}grandfather->_col = RED;parent->_col = BLACK;_RotateL(grandfather);}}}_root->_col = BLACK;return true;}void _RotateL(Node* parent)//左旋转{Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;//修改指针(1)if (subRL)subRL->_parent = parent;subR->_left = parent;    //修改指针(2)subR->_parent = parent->_parent;parent->_parent = subR;if (subR->_parent == NULL){_root = subR;}else{if (subR->_parent->_key > subR->_key){subR->_parent->_left = subR;//修改指针(3)}else{subR->_parent->_right = subR;}}}void _RotateR(Node* parent)    //右旋{Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR){subLR->_parent = parent;}subL->_right = parent;subL->_parent = parent->_parent;parent->_parent = subL;if (subL->_parent == NULL){_root = subL;}else{if (subL->_parent->_key > subL->_key){subL->_parent->_left = subL;}else{subL->_parent->_right = subL;}}}void InOrder(){return _InOrder(_root);}void _InOrder(Node* root){if (root == NULL){return;}_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}protected:Node* _root;};

以上仅是红黑树的插入操作和打印操作,希望以上代码能帮助到想学编程的童鞋。

0 0
原创粉丝点击