[数据结构]红黑树,详细图解插入
- IT业界
- 2025-09-03 00:00:01
![[数据结构]红黑树,详细图解插入](/0pic/pp_34.jpg)
目录
一、红黑树的概念
二、红黑树的性质
三、红黑树节点的定义
四、红黑树的插入(步骤)
1.为什么新插入的节点必须给红色?
2、插入红色节点后,判定红黑树性质是否被破坏
五、插入出现连续红节点情况分析+图解(看uncle节点)
5.1、uncle存在且为红
5.2、uncle不存在
1、单旋
2、双旋
5.3、uncle存在且为黑
1、单旋
2、双旋
六、插入总结
1、红黑树插入的两种步骤
2、插入代码
七、红黑树总结及代码
一、红黑树的概念
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或 Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,
红黑树确保——没有一条路径会比其他路径长出两倍,因而是接近平衡的
二、红黑树的性质
1. 每个结点不是红色就是黑色
2. 根节点是黑色的
3. 如果一个节点是红色的,则它的两个孩子结点是黑色的 (没有连续的红节点)
4. 从任一结点到其所有后代叶结点的简单路径上,均包含相同数目的黑结点
5. 每个叶子结点都是黑色的(此处的叶子结点指的是NIL空结点)
最优情况:全黑或每条路径都是一黑一红的满二叉树,高度logN
最差情况:每颗子树左子树全黑,右子树一黑一红。高度2*logN。
可以发现,最坏情况的时间复杂度和AVL树一样,都是O(logN),但是红黑树这种近似平衡的结构减少了大量旋转,综合性能优于AVL树。
三、红黑树节点的定义 enum Colour { RED, BLACK }; template<class K, class V> struct RBTreeNode { RBTreeNode<K, V>* _left; RBTreeNode<K, V>* _right; RBTreeNode<K, V>* _parent; pair<K, V> _kv; Colour _col; RBTreeNode(const pair<K, V>& kv) :_left(nullptr) , _right(nullptr) , _parent(nullptr) , _kv(kv) , _col(RED) {} };
四、红黑树的插入(步骤) 1.为什么新插入的节点必须给红色?
(1)新节点给红色,可能出现连续红节点
(2)如果新节点给黑色,必定会违反性质4(其每条路径的黑色节点数量相同)
2、插入红色节点后,判定红黑树性质是否被破坏因为新节点的默认颜色是红色,所以
(1)双亲节点的颜色是黑色,没有违反红黑树任何 性质,则不需要调整;
(2)双亲节点为红色,就会出现连续的红节点,此时需要对红黑树分情况来讨论:见下一部分
五、插入出现连续红节点情况分析+图解(看uncle节点)
约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点
下面的分析都是以p为g的左孩子为例
5.1、uncle存在且为红cur插入后,p和u变黑,g变红
(1)g没有父亲,g为根,g变黑
(2)g有父亲。其为黑,结束;其为红,后把g当成cur,继续向上调整
5.2、uncle不存在u不存在,则cur一定是新插入的节点。
(如果cur不是新插入的节点,则cur和p一定有一个节点是黑色,否则每条路径黑色节点不相同)
下图为解释:
1、单旋右单旋
2、双旋左单旋 + 右单旋
5.3、uncle存在且为黑uncle存在且为黑,是情况一变来的,所以cur原来的节点一定是黑色的。
现在其是红色的原因是,cur的子树在调整过程中将cur的颜色由黑变红。
1、单旋右单旋
2、双旋左单旋 + 右单旋
六、插入总结 1、红黑树插入的两种步骤1、uncle存在且为红
2、uncle不存在 或者 uncle存在且为黑
通过分析,
uncle不存在的单旋 和 uncle存在且为黑的单旋 可以写在一起,
uncle不存在的双旋 和 uncle存在且为黑的双旋 可以写在一起,
不论uncle存在或者不存在,都不影响此步的单旋或者双旋。
当p为g的右孩子时,操作都相反。
详细步骤见其中while (parent && parent->_col == RED)这一步。
2、插入代码 bool Insert(const pair<K, V>& kv) { if (_root == nullptr) { _root = new Node(kv); _root->_col = BLACK; return true; } Node* parent = nullptr; Node* cur = _root; while (cur) { if (cur->_kv.first < kv.first) { parent = cur; cur = cur->_right; } else if (cur->_kv.first > kv.first) { parent = cur; cur = cur->_left; } else { return false; } } cur = new Node(kv); cur->_col = RED; if (parent->_kv.first < kv.first) { parent->_right = cur; } else { parent->_left = cur; } cur->_parent = parent; while (parent && parent->_col == RED) { Node* grandfather = parent->_parent; //p为g左孩子 if (parent == grandfather->_left) { Node* uncle = grandfather->_right; // 情况1:u存在且为红 if (uncle && uncle->_col == RED) { // 变色 parent->_col = uncle->_col = BLACK; grandfather->_col = RED; // 继续向上处理 cur = grandfather; parent = cur->_parent; } else // u不存在 或 存在且为黑 { //情况2.1 , 3.1 if (cur == parent->_left) { // g // p // c RotateR(grandfather); parent->_col = BLACK; grandfather->_col = RED; } else//情况2.2 , 3.2 { // g // p // c RotateL(parent); RotateR(grandfather); cur->_col = BLACK; grandfather->_col = RED; } break; } } //p为g右孩子 else // parent == grandfather->_right { Node* uncle = grandfather->_left; // u存在且为红 if (uncle && uncle->_col == RED) { // 变色 parent->_col = uncle->_col = BLACK; grandfather->_col = RED; // 继续向上处理 cur = grandfather; parent = cur->_parent; } else { if (cur == parent->_right) { // g // p // c RotateL(grandfather); grandfather->_col = RED; parent->_col = BLACK; } else { // g // p // c RotateR(parent); RotateL(grandfather); cur->_col = BLACK; grandfather->_col = RED; } break; } } } _root->_col = BLACK; return true; }七、红黑树总结及代码
红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O(logN),红黑树不追求绝对平衡,只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数, 所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。
using namespace std; enum Colour { RED, BLACK }; template<class K, class V> struct RBTreeNode { RBTreeNode<K, V>* _left; RBTreeNode<K, V>* _right; RBTreeNode<K, V>* _parent; pair<K, V> _kv; Colour _col; RBTreeNode(const pair<K, V>& kv) :_left(nullptr) , _right(nullptr) , _parent(nullptr) , _kv(kv) , _col(RED) {} }; template<class K, class V> struct RBTree { typedef RBTreeNode<K, V> Node; public: bool Insert(const pair<K, V>& kv) { if (_root == nullptr) { _root = new Node(kv); _root->_col = BLACK; return true; } Node* parent = nullptr; Node* cur = _root; while (cur) { if (cur->_kv.first < kv.first) { parent = cur; cur = cur->_right; } else if (cur->_kv.first > kv.first) { parent = cur; cur = cur->_left; } else { return false; } } cur = new Node(kv); cur->_col = RED; if (parent->_kv.first < kv.first) { parent->_right = cur; } else { parent->_left = cur; } cur->_parent = parent; while (parent && parent->_col == RED) { Node* grandfather = parent->_parent; //p为g左孩子 if (parent == grandfather->_left) { Node* uncle = grandfather->_right; // 情况1:u存在且为红 if (uncle && uncle->_col == RED) { // 变色 parent->_col = uncle->_col = BLACK; grandfather->_col = RED; // 继续向上处理 cur = grandfather; parent = cur->_parent; } else // u不存在 或 存在且为黑 { //情况2.1 , 3.1 if (cur == parent->_left) { // g // p // c RotateR(grandfather); parent->_col = BLACK; grandfather->_col = RED; } else//情况2.2 , 3.2 { // g // p // c RotateL(parent); RotateR(grandfather); cur->_col = BLACK; grandfather->_col = RED; } break; } } //p为g右孩子 else // parent == grandfather->_right { Node* uncle = grandfather->_left; // u存在且为红 if (uncle && uncle->_col == RED) { // 变色 parent->_col = uncle->_col = BLACK; grandfather->_col = RED; // 继续向上处理 cur = grandfather; parent = cur->_parent; } else { if (cur == parent->_right) { // g // p // c RotateL(grandfather); grandfather->_col = RED; parent->_col = BLACK; } else { // g // p // c RotateR(parent); RotateL(grandfather); cur->_col = BLACK; grandfather->_col = RED; } break; } } } _root->_col = BLACK; return true; } void RotateL(Node* parent) { ++_rotateCount; Node* cur = parent->_right; Node* curleft = cur->_left; parent->_right = curleft; if (curleft) { curleft->_parent = parent; } cur->_left = parent; Node* ppnode = parent->_parent; parent->_parent = cur; if (parent == _root) { _root = cur; cur->_parent = nullptr; } else { if (ppnode->_left == parent) { ppnode->_left = cur; } else { ppnode->_right = cur; } cur->_parent = ppnode; } } void RotateR(Node* parent) { ++_rotateCount; Node* cur = parent->_left; Node* curright = cur->_right; parent->_left = curright; if (curright) curright->_parent = parent; Node* ppnode = parent->_parent; cur->_right = parent; parent->_parent = cur; if (ppnode == nullptr) { _root = cur; cur->_parent = nullptr; } else { if (ppnode->_left == parent) { ppnode->_left = cur; } else { ppnode->_right = cur; } cur->_parent = ppnode; } } bool CheckColour(Node* root, int blacknum, int benchmark) { if (root == nullptr) { if (blacknum != benchmark) return false; return true; } if (root->_col == BLACK) { ++blacknum; } if (root->_col == RED && root->_parent && root->_parent->_col == RED) { cout << root->_kv.first << "出现连续红色节点" << endl; return false; } return CheckColour(root->_left, blacknum, benchmark) && CheckColour(root->_right, blacknum, benchmark); } bool IsBalance() { return IsBalance(_root); } bool IsBalance(Node* root) { if (root == nullptr) return true; if (root->_col != BLACK) { return false; } // 基准值 int benchmark = 0; Node* cur = _root; while (cur) { if (cur->_col == BLACK) ++benchmark; cur = cur->_left; } return CheckColour(root, 0, benchmark); } int Height() { return Height(_root); } int Height(Node* root) { if (root == nullptr) return 0; int leftHeight = Height(root->_left); int rightHeight = Height(root->_right); return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1; } private: Node* _root = nullptr; public: int _rotateCount = 0; };[数据结构]红黑树,详细图解插入由讯客互联IT业界栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“[数据结构]红黑树,详细图解插入”
下一篇
iOS上自定义编译FFmpeg