编程语言
123
一、红黑树简介
红黑树的规则有
1.每个节点不是红色就是黑色 2.根节点是黑色 3.如果一个节点是红色,它的两个孩子节点是黑色 4.每条路径都有相同数量的黑色节点 5.叶子节点(Nullptr节点)是黑的
这些规则可以推导出红黑树的特性
其最长路径不超过最短路径的两倍,近似平衡 没有连续的红节点 左右子树的黑节点个数相同
其相较于AVL树并没有过多的旋转 用较不平衡换取了性能
在实际中,红黑树的应用相较于AVL树更加常用
二、红黑树的模拟实现
#pragma once #include<iostream> using namespace std; enum Color { Red, Black }; template<class K, class V> struct RBTreeNode { RBTreeNode* _left; RBTreeNode* _right; RBTreeNode* _parent; Color _col; pair<K, V> _kv; RBTreeNode(const pair<K, V>& kv) :_left(nullptr) , _right(nullptr) , _parent(nullptr) , _col(Red) , _kv(kv) {} //定义一个节点时要注意其颜色:不过黑红的地位有所不同,选择决定后续的执行是否简单 //选择红色:违背红色不能连续出现 //选择黑色:违背整体路径黑色数量一致 //红色更好,红色调节节点即可,黑色调节整个路径 }; template<class K, class V> class 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* cur = _root; Node* parent = nullptr; while (cur) { if (cur->_kv.first > kv.first) { parent = cur; cur = cur->_left; } else if (cur->_kv.first < kv.first) { parent = cur; cur = cur->_right; } else { return false; } } //找到需要插入的位置后 cur = new Node(kv); //默认插入为红色 if (cur->_kv.first > parent->_kv.first) parent->_right = cur; else parent->_left = cur; cur->_parent = parent; //开始处理颜色 while (parent && parent->_col == Red) // { Node* grandpa = parent->_parent; //分两种情况,更方便旋转,父在左 or 父在右 if (grandpa->_left == parent) //父在左 { Node* uncle = grandpa->_right; //情况1:uncle不为空且为红色 //parent和uncle变黑,grandpa变红 //grandpa的父亲为黑,停止 //grandpa的父亲为红,继续向上 if (uncle && uncle->_col == Red) //uncle不为空且为红 { parent->_col = uncle->_col = Black; grandpa->_col = Red; cur = grandpa; grandpa = cur->_parent; } //情况2:uncle为空或者为黑色 else { if (cur == parent->_right) //此时需要双旋 { RotateL(parent); //左旋 swap(parent, cur); //cur和parent进行交换,使得变得和单旋时的条件一样,一举两得 } RotateR(grandpa); parent->_col = Black; grandpa->_col = Red; } break; //处理完直接跳出来 } else //父在右 { Node* uncle = grandpa->_left; if (uncle && uncle->_col == Red) { parent->_col = uncle->_col = Black; grandpa->_col = Red; cur = grandpa; grandpa = cur->_parent; } else { if (cur == parent->_left) //双旋 { RotateR(parent); swap(parent, cur); } RotateL(grandpa); grandpa->_col = Red; parent->_col = Black; } break; } } _root->_col = Black; //确保根节点为黑,流氓方法 return true; } void Print() { _Print(_root); } bool Inspect() { return _Inspect(_root); } private: Node* _root = nullptr; void _Print(Node*& cur) { if (cur == nullptr) return; _Print(cur->_left); cout << cur->_kv.first << " "; _Print(cur->_right); } void RotateL(Node*& parent) { Node* pparent = parent->_parent; Node* subR = parent->_right; Node* subRL = subR->_left; if (pparent == nullptr) { _root = subR; subR->_parent = nullptr; } else { if (pparent->_left == parent) pparent->_left = subR; else pparent->_right = subR; subR->_parent = pparent; } parent->_parent = subR; subR->_left = parent; parent->_right = subRL; if (subRL != nullptr) subRL->_parent = parent; } void RotateR(Node*& parent) { Node* pparent = parent->_parent; Node* subL = parent->_left; Node* subLR = subL->_right; if (pparent == nullptr) { _root = subL; subL->_parent = nullptr; } else { if (pparent->_left == parent) pparent->_left = subL; else pparent->_right = subL; subL->_parent = pparent; } parent->_parent = subL; subL->_right = parent; parent->_left = subLR; if (subLR != nullptr) subLR->_parent = parent; } bool check(Node* root, size_t& reference, size_t num) { if (root == nullptr) { if (num != reference) { cout << "路径长度有问题" << endl; return false; } return true; } if (root->_col == Red && root->_parent && root->_parent->_col == Red) { cout << "节点连续红色" << endl; return false; } if (root->_col == Black) num++; return check(root->_left, reference, num) && check(root->_right, reference, num); } bool _Inspect(Node* root) { //空树也是红黑树 if (_root == nullptr) return true; //检测根节点是否为黑色 if (_root->_col != Black) { cout << "根节点是红色的" << endl; return false; } size_t leftNum = 0; Node* cur = _root; while (cur) { if (cur->_col == Black) leftNum++; cur = cur->_left; } //检测所有路径黑色节点的数量是否一样 //检测相邻节点是不是都是红色的 return check(_root, leftNum, 0); } };