目录
回顾
情况
局部解决办法
全局解决的思想
代码
深入到叶子节点准备插入新数据
准备插入数据
插入
出现本章情况
祖父节点赋值
叔叔节点赋值
变色——进行平衡性调整
总代码
注意事项
总结
回顾
上一章
C++红黑树(1/4)_木木em哈哈的博客-CSDN博客 https://blog.csdn.net/mumuemhaha/article/details/131152321?spm=1001.2014.3001.5501
下一章
红黑树c++(3/4)_木木em哈哈的博客-CSDN博客 https://blog.csdn.net/mumuemhaha/article/details/131191005?spm=1001.2014.3001.5501
上一章学到了红黑树的特点以及基本定义
本章我们要学插入时候的第一类情况——父亲节点为红色叔叔节点也为红(当然祖父节点一定为黑色)
情况
当我的红色节点插上去时因为特性二——红色节点不可以相邻出现从而要对整个树进行平衡性调整
我们可以把新节点的颜色不变,然后把父亲节点和叔叔节点的颜色变为黑色,然后把爷爷节点的颜色变为红色
局部解决办法
从而达到这棵树的平衡
需要注意的是如果祖父是根节点的话要把祖父的颜色也调为黑色
全局解决的思想
然而不幸的是一颗树的深度不仅仅可以是3,他可以更深——4,5,,6,7…或者更多
如图
要在这个红黑树上把插入一个新的红色节点
那么还是安装之前的方法调整你会发现一个问题就是你插入节点的祖父节点的父亲节点(也就是你的曾祖父节点)是红色的且你祖父节点的叔叔节点是黑色不在这一类方法中
如图
但是不要慌张,后面两节会讲到其他的情况以及应对的方法(需要注意的时在后续解决中你要把蓝圈部分当成一个整体【因为他已经平衡了】)
现在恭喜你,你已经学到了红黑树插入时会遇到的第一种情况的解决办法
接下来就是代码讲解了
代码
首先我要创建一个RBTree(红黑树)的类
分别有lchild(左孩子)rchild(右孩子)parent(父母节点)data(自身的数据)color(颜色)
这几个类别除去color为RED(红色)其他全为空(nullptr)上一章讲过了
深入到叶子节点准备插入新数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 while (point->data==nullptr ){ if (e == point->data) { printf ("该数据已经存在" ); return ; } parent = point; if (e >= point) point = point->rchild; else point = point->lchild; }
和其他的树一样,大的在右边,小的在左边重复数据插不了
每次保存其父亲节点
在一次次遍历中一直找到最深层
准备插入数据
接下来就是初始化数据
除了colour其他全为空
1 2 3 4 5 6 point = new RBNode<T>; point->data = e; point->lchild = nullptr ; point->rchild = nullptr ; point->parent = nullptr ; point->colour = RED;
需要注意的是如果为根节点那么colour还是要改为黑色
1 2 3 4 5 6 if (parent == nullptr ){ point->colour = BLACK; tnode = point; }
插入
插入,接下来就是链接他的父亲节点
依照data的大小来判断插入左孩子还是右孩子
并且当父亲节点为黑色时不用判断直接插入完成返回
1 2 3 4 5 6 7 8 9 10 11 if (e > parent->data) parent->rchild = point; else parent->lchild = point; point->parent = parent; if (parent->colour == BLACK){ count << e << "插入完成" << endl; return ; }
出现本章情况
那么首先要创建其叔叔节点以及祖父节点并开始赋值
1 2 RBNode<T>* uncle = nullptr ; RBNode<T>* grandpa = nullptr ;
祖父节点赋值
祖父节点简单就是父亲的父亲
1 grandpa = point->parent->parent;
叔叔节点赋值
而叔叔节点麻烦一点
最好创建一个函数用来获取其叔叔节点
1 uncle = (parent->parent != nullptr ) ? (getuncle (parent) :nullptr );
那么getuncle()函数定义就为
1 2 3 4 5 6 7 RBNode<T>* getuncle (RBNode<T>* p) { if (p->parent->lchild == p) return p->parent->rchild; else return p->parent->rchild; }
需要注意的是获取叔叔节点的函数最好放在private(确保函数是私有的)
变色——进行平衡性调整
最后变颜色
在获取到了叔叔以及祖父节点后接下的工作就变得简单了
按照上面的图片依葫芦画瓢去变色就行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 while (true ){ uncle = (parent->parent != nullptr ) ? (getuncle (parent) :nullptr ); grandpa = point->parent->parent; if grandpa == nullptr break ; if (uncle != nullptr && uncle->colour == RED) { parent->colour = BLACK; uncle->colour = BLACK; grandpa->colour = RED; if (grandpa == root) grandpa->colour = BLACK; } } root->colour = BLACK;
总代码
最后附上调整后的源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 #include <iostream> using namespace std;enum Colour { RED, BLACK, }; template <typename T>struct RBNode { RBNode* lchild, * rchild, * parent; T data; Colour colour=RED; }; template <typename T>class RBTree { public : RBTree () { root = nullptr ; } ~RBTree () { ReleaseNode (root); } void InsNode (const T& e) { InsNode (root, e); } void InsNode (RBNode<T>*& tnode, const T& e) { RBNode<T>* point = tnode; RBNode<T>* parent = nullptr ; while (point->data==nullptr ) { if (e == point->data) { printf ("该数据已经存在" ); return ; } parent = point; if (e >= point) point = point->rchild; else point = point->lchild; } point = new RBNode<T>; point->data = e; point->lchild = nullptr ; point->rchild = nullptr ; point->parent = nullptr ; point->colour = RED; if (parent == nullptr ) { point->colour = BLACK; tnode = point; } if (e > parent->data) parent->rchild = point; else parent->lchild = point; point->parent = parent; if (parent->colour == BLACK) { count << e << "插入完成" << endl; return ; } RBNode<T>* uncle = nullptr ; RBNode<T>* grandpa = nullptr ; while (true ) { uncle = (parent->parent != nullptr ) ? (getuncle (parent) :nullptr ); grandpa = point->parent->parent; if grandpa == nullptr break ; if (uncle != nullptr && uncle->colour == RED) { parent->colour = BLACK; uncle->colour = BLACK; grandpa->colour = RED; if (grandpa == root) grandpa->colour = BLACK; } point = grandpa; parent = grandpa->parent; if (parent->colour == BLACK) break ; continue ; } root->colour = BLACK; } private : void ReleaseNode (RBNode<T>* pnode) { if (pnode != nullptr ) { ReleaseNode (pnode->lchild); ReleaseNode (pnode->rchild); } delete pnode; } RBNode<T>* getuncle (RBNode<T>* p) { if (p->parent->lchild == p) return p->parent->rchild; else return p->parent->rchild; } private : RBNode <T>* root; }; int main () { printf ("OK" ); return 0 ; }
注意事项
需要注意的是,代码打上去目前还不能跑,原因就和上面说的一样——还有一些其他情况我们无法解决,需要继续学习接下来的两类情况。
总结
恭喜你,已经初步学会了红黑树的第一种平衡性调整,即使还有一些情况还不知道,但是请不要担心,后面的文章会教你如何去做。