当前位置: 首页 > news >正文

弹幕网站用什么做通化好的网站建设的公司

弹幕网站用什么做,通化好的网站建设的公司,综合网站开发,初学者制作网页用什么软件前言 【C】二叉树进阶#xff08;二叉搜索树#xff09; 这篇文章讲述了关于二叉搜索树知识#xff0c;但是二叉搜索树有其自身的缺陷#xff0c;假如往树中插入的元素有序或者接近有序#xff0c;二叉搜索树就会退化成单支树#xff0c;时间复杂度会退化成O(N)#xff… 前言 【C】二叉树进阶二叉搜索树 这篇文章讲述了关于二叉搜索树知识但是二叉搜索树有其自身的缺陷假如往树中插入的元素有序或者接近有序二叉搜索树就会退化成单支树时间复杂度会退化成O(N)因此map、set等关联式容器的底层结构是对二叉树进行了平衡处理即采用平衡树来实现AVL树和红黑树都在不同程度下优化了二叉搜索树。在这篇文章中 【C】─篇文章带你熟练掌握 map 与 set 的使用 我们对map与set的使用进行了详细的讲解那么这篇文章会在实现AVL树的基础上对map与set进行封装。 目录 一、AVL 树1.1 AVL树的概念1.2 AVL树节点的定义1.3 AVL树的插入1.4 AVL树的旋转1.4.1 新节点插入较高左子树的左侧----左左高右单旋1.4.2 新节点插入较高右子树的右侧----右右高左单旋1.4.3 新节点插入较高左子树的右侧---左右高先左单旋再右单旋1.4.4 新节点插入较高右子树的左侧---右左高先右单旋再左单旋 1.5 AVL树的验证1.6 AVL树的性能1.7 AVL树的整体实现 二、红黑树2.1 红黑树的概念2.2 红黑树的性质2.3 红黑树节点的定义2.4 红黑树的结构2.5 红黑树的插入操作2.6 红黑树的验证2.7 红黑树与AVL树的比较 三、红黑树的模拟实现3.1 红黑树中迭代器的实现3.2 红黑树中clear、size 和 empty 的实现3.3 获得红黑树中的最左/右节点3.4 红黑树中 begin 和 end 的实现3.5 红黑树中 insert 的实现3.6 红黑树中 find 的实现3.7 红黑树的整体实现 四、set 和 map 的封装4.1 set的封装4.2 map的封装 结尾 一、AVL 树 1.1 AVL树的概念 二叉搜索树虽可以缩短查找的效率但如果数据有序或接近有序二叉搜索树将退化为单支树查 找元素相当于在顺序表中搜索元素效率低下。因此两位俄罗斯的数学家G.M.Adelson-Velskii 和E.M.Landis在1962年发明了一种解决上述问题的方法当向二叉搜索树中插入新结点后如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整)即可降低树的高度从而减少平均搜索长度。 一棵AVL树或者是空树或者是具有以下性质的二叉搜索树 它或是它的左右子树都是AVL树左右子树的高度差平衡因子的绝对值不超过1 如果一棵二叉搜索树是高度平衡的它就是AVL树。如果它有n个结点其高度可保持在 O ( l o g 2 n ) O(log_2 n) O(log2​n)搜索时间复杂度O( l o g 2 n log_2 n log2​n) 1.2 AVL树节点的定义 由于AVL树比红黑树稍逊一筹后面set和map的封装不会使用AVL树所以这里AVL树将会简单的进行编写。 templateclass K, class V struct AVLTreeNode {AVLTreeNode* _left;AVLTreeNode* _right;AVLTreeNode* _parent;pairK, V _kv;int _bf; // 平衡因子AVLTreeNode(const pairK, V kv): _left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _bf(0){} };1.3 AVL树的插入 AVL树就是在二叉搜索树的基础上引入了平衡因子因此AVL树也可以看成是二叉搜索树。那么 AVL树的插入过程可以分为两步 找到新节点应该插入的位置进行链接(这里写的AVL树不允许插入相同的元素)插入新节点后若出现某棵树的平衡因子异常的情况则需要进行调整 这里的左旋、右旋等在下面AVL树的旋转进行讲解 templateclass K, class V class AVLTree {typedef AVLTreeNodeK, V Node; public:bool Insert(const pairK, V kv){if (_root nullptr){_root new Node(kv);return true;}Node* parent nullptr;Node* cur _root;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;}// 有相同的K插入失败else{return false;}}// 插入新节点cur new Node(kv);if (parent-_kv.first cur-_kv.first){parent-_left cur;cur-_parent parent;}else{parent-_right cur;cur-_parent parent;}// 平衡旋转while (parent){if (parent-_left cur){parent-_bf--;}else{parent-_bf;}// 如果当前树插入新节点后的平衡因子变为0// 那么说明新插入的节点并没有使当前树的高度增加// 更不会对当前节点到根节点路径上节点的平衡因子造成影响// 所以说这里break不需要继续处理if (parent-_bf 0){break;}// 当父节点的平衡因子为1/-1时那么说明这个新插入的节点影响了父节点的高度// 也有可能影响新插入节点以上节点的平衡因子向上判断该节点是否影响上面树的平衡性// 若影响上面树的平衡性那么需要旋转来平衡树使其平衡else if (parent-_bf 1 || parent-_bf -1){if (parent _root)break;cur parent;parent parent-_parent;}else if (parent-_bf 2 || parent-_bf -2){// 右右高左单旋if (parent-_bf 2 cur-_bf 1){RotateL(parent);break;}// 左左高右单旋else if (parent-_bf -2 cur-_bf -1){RotateR(parent);break;}// 右左高右左双旋先将当前节点右单旋再将父亲节点左单旋else if (parent-_bf 2 cur-_bf -1){RotateRL(parent);break;}// 左右高左右双旋先将当前节点左单旋再将父亲节点右旋单旋else if (parent-_bf -2 cur-_bf 1){RotateLR(parent);break;}else{assert(false);}}// 当父亲节点的平衡因子为其他值时那么这棵树一定是出现了问题else{assert(false);}}return true;}private:Node* _root nullptr; };1.4 AVL树的旋转 1.4.1 新节点插入较高左子树的左侧----左左高右单旋 这里无论是在t1还是t2插入一个新节点都是右单旋只有平衡因子的区别这里介绍一下再t1的情况。 t1、t2和t3都是高度为 hh0 的AVL树首先在新节点未插入时节点10的平衡因子为0节点20的平衡因子为-1此时所有树都满足AVL树的条件。当在t1上插入一个节点就导致节点10的平衡因子为-1,节点20的平衡因子为-2此时节点20为根的这颗数违反了AVL树的规则需要进行选择调整。 首先t2这颗树上的节点都是比20小、比10大的节点使t2变为节点20的左再将节点20变为节点10的右就能够使整体树的高度与之前的一样但是这里的树可能是一颗完整的树也有可能是一颗子树若是子树需要处理好旋转后与上面节点的连接问题详细的如何连接大家可以看下面代码。 注意当树进行旋转后树中的某些节点的平衡因子会进行变化所以大家在旋转后需要对节点的平衡因子做好调整。 templateclass K, class V class AVLTree {typedef AVLTreeNodeK, V Node; private:// 右单旋void RotateR(Node* parent){Node* subL parent-_left;Node* subLR subL-_right;parent-_left subLR;if (subLR)subLR-_parent parent;Node* Pparent parent-_parent;subL-_right parent;parent-_parent subL;if (parent _root){_root subL;subL-_parent nullptr;}else{subL-_parent Pparent;if (Pparent-_left parent){Pparent-_left subL;}else{Pparent-_right subL;}}parent-_bf subL-_bf 0;}Node* _root nullptr; };1.4.2 新节点插入较高右子树的右侧----右右高左单旋 这里无论是在t2还是t3插入一个新节点都是左单旋只有平衡因子的区别这里介绍一下再t3的情况。 t1、t2和t3都是高度为 hh0 的AVL树首先在新节点未插入时节点20的平衡因子为0节点10的平衡因子为1此时所有树都满足AVL树的条件。当在t3上插入一个节点就导致节点20的平衡因子为1节点10的平衡因子为2,此时节点20为根的这颗数违反了AVL树的规则需要进行选择调整。 首先t2这颗树上的节点都是比20小、比10大的节点使t2变为节点10的右再将节点10变为节点20的左就能够使整体树的高度与之前的一样但是这里的树可能是一颗完整的树也有可能是一颗子树若是子树需要处理好旋转后与上面节点的连接问题详细的如何连接大家可以看下面代码。 注意当树进行旋转后树中的某些节点的平衡因子会进行变化所以大家在旋转后需要对节点的平衡因子做好调整。 templateclass K, class V class AVLTree {typedef AVLTreeNodeK, V Node; private:// 左单旋void RotateL(Node* parent){Node* subR parent-_right;Node* subRL subR-_left;parent-_right subRL;if (subRL)subRL-_parent parent;Node* Pparent parent-_parent;parent-_parent subR;subR-_left parent;if (parent _root){_root subR;subR-_parent nullptr;}else{subR-_parent Pparent;if (Pparent-_left parent){Pparent-_left subR;}else{Pparent-_right subR;}}parent-_bf subR-_bf 0;}Node* _root nullptr; };1.4.3 新节点插入较高左子树的右侧—左右高先左单旋再右单旋 这里无论是在t2还是t3插入一个新节点都是左右双旋只有平衡因子的区别所以这里只画了在插入t3插入的这种情况插入t2的情况大家可以自己下来试试。 t1、t4是高度为 h 的AVL树t2和t3都是高度为 h-1h1 的AVL树首先在新节点未插入时节点20的平衡因子为0节点10的平衡因子为0节点30的平衡因子为-1此时所有树都满足AVL树的条件。当在t3上插入一个节点就导致节点20的平衡因子为1节点10的平衡因子为1节点30的平衡因子为-2,此时节点30为根的这颗数违反了AVL树的规则需要进行旋转调整。 当我们知道这里需要进行旋转调整但是只有一边高的时候能够使用单旋而这里是两边高那么这里就将将这棵树处理为一边高就可以使用单旋了。 看下图首先这里对节点10这棵树使用左单旋就可以使节点30的这棵树变为只有左左高再对节点30这棵树进行右单旋这么做能够使整体树的高度与之前的一样但是这里的树可能是一颗完整的树也有可能是一颗子树若是子树需要处理好旋转后与上面节点的连接问题详细的如何连接大家可以看下面代码。 注意当树进行旋转后树中的某些节点的平衡因子会进行变化所以大家在旋转后需要对节点的平衡因子做好调整。 templateclass K, class V class AVLTree {typedef AVLTreeNodeK, V Node; private:// 左右双旋void RotateLR(Node* parent){Node* subL parent-_left;Node* subLR subL-_right;int bf subLR-_bf;RotateL(subL);RotateR(parent);if (bf 0){parent-_bf subL-_bf subLR-_bf 0;}else if (bf -1){parent-_bf 1;subL-_bf 0;subLR-_bf 0;}else if (bf 1){subL-_bf -1;parent-_bf 0;subLR-_bf 0;}}Node* _root nullptr; };1.4.4 新节点插入较高右子树的左侧—右左高先右单旋再左单旋 这里无论是在t2还是t3插入一个新节点都是右左双旋只有平衡因子的区别所以这里只画了在插入t3插入的这种情况插入t2的情况大家可以自己下来试试。 t1、t4是高度为 h 的AVL树t2和t3都是高度为 h-1h1 的AVL树首先在新节点未插入时节点20的平衡因子为0节点30的平衡因子为0节点10的平衡因子为1此时所有树都满足AVL树的条件。当在t3上插入一个节点就导致节点20的平衡因子为1节点30的平衡因子为-1,节点10的平衡因子为2,此时节点30为根的这颗数违反了AVL树的规则需要进行旋转调整。 当我们知道这里需要进行旋转调整但是只有一边高的时候能够使用单旋而这里是两边高那么这里就将将这棵树处理为一边高就可以使用单旋了。 看下图首先这里对节点20这棵树使用右单旋就可以使节点10的这棵树变为只有右右高再对节点10这棵树进行左单旋这么做能够使整体树的高度与之前的一样但是这里的树可能是一颗完整的树也有可能是一颗子树若是子树需要处理好旋转后与上面节点的连接问题详细的如何连接大家可以看下面代码。 注意当树进行旋转后树中的某些节点的平衡因子会进行变化所以大家在旋转后需要对节点的平衡因子做好调整。 templateclass K, class V class AVLTree {typedef AVLTreeNodeK, V Node; private:// 右左双旋void RotateRL(Node* parent){Node* subR parent-_right;Node* subRL subR-_left;int bf subRL-_bf;RotateR(subR);RotateL(parent);if (bf 0){parent-_bf subR-_bf subRL-_bf 0;}else if (bf -1){subRL-_bf 0;parent-_bf 0;subR-_bf 1;}else if (bf 1){subRL-_bf 0;parent-_bf -1;subR-_bf 0;}}Node* _root nullptr; };1.5 AVL树的验证 AVL树是在二叉搜索树的基础上加入了平衡性的限制因此要验证AVL树可以分两步 验证其为二叉搜索树 如果中序遍历可得到一个有序的序列就说明为二叉搜索树验证其为平衡树 (a) 每个节点子树高度差的绝对值不超过1(注意节点中如果没有平衡因子) (b) 节点的平衡因子是否计算正确 在下面函数的实现中大家可以发现都嵌套了一个函数由于函数按照递归实现的而递归的实现是需要根节点的封装外是无法访问的根节点的但是封装内是可以直接访问根节点的所以嵌套了一层。 templateclass K, class V class AVLTree {typedef AVLTreeNodeK, V Node; public:// 中序变量void InOrder(){_InOrder(_root);}// 判断是否为AVL树bool IsBalance(){return _IsBalance(_root);}// 计算树的高度int Height(){return _Height(_root);}private:bool _IsBalance(Node* root){if (root nullptr)return true;bool left _IsBalance(root-_left);if (!left) return left;bool right _IsBalance(root-_right);if (!right) return right;if (_Height(root-_right) - _Height(root-_left) ! root-_bf)cout root-_kv.first : 平衡因子异常 endl;return left right abs(_Height(root-_left) - _Height(root-_right) 2);}int _Height(Node* root){if (root nullptr)return 0;int left _Height(root-_left);int right _Height(root-_right);return left right ? left 1 : right 1;}void _InOrder(Node* root){if (root nullptr)return;_InOrder(root-_left);cout root-_kv.first endl;_InOrder(root-_right);}Node* _root nullptr; };1.6 AVL树的性能 AVL树是一棵绝对平衡的二叉搜索树其要求每个节点的左右子树高度差的绝对值都不超过1这样可以保证查询时高效的时间复杂度即 l o g 2 ( N ) log_2 (N) log2​(N)。但是如果要对AVL树做一些结构修改的操作性能非常低下比如插入时要维护其绝对平衡旋转的次数比较多更差的是在删除时有可能一直要让旋转持续到根的位置。因此如果需要一种查询高效且有序的数据结构而且数据的个数为静态的(即不会改变)可以考虑AVL树但一个结构经常修改就不太适合。 1.7 AVL树的整体实现 #pragma once#include iostream #include assert.h #include vector #include stringusing namespace std;templateclass K, class V struct AVLTreeNode {AVLTreeNode* _left;AVLTreeNode* _right;AVLTreeNode* _parent;pairK, V _kv;int _bf; // 平衡因子AVLTreeNode(const pairK, V kv): _left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _bf(0){} };templateclass K, class V class AVLTree {typedef AVLTreeNodeK, V Node; public:bool Insert(const pairK, V kv){if (_root nullptr){_root new Node(kv);return true;}Node* parent nullptr;Node* cur _root;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;}// 有相同的K插入失败else{return false;}}// 插入新节点cur new Node(kv);if (parent-_kv.first cur-_kv.first){parent-_left cur;cur-_parent parent;}else{parent-_right cur;cur-_parent parent;}// 平衡旋转while (parent){if (parent-_left cur){parent-_bf--;}else{parent-_bf;}// 如果当前树插入新节点后的平衡因子变为0// 那么说明新插入的节点并没有使当前树的高度增加// 更不会对当前节点到根节点路径上节点的平衡因子造成影响// 所以说这里break不需要继续处理if (parent-_bf 0){break;}// 当父节点的平衡因子为1/-1时那么说明这个新插入的节点影响了父节点的高度// 也有可能影响新插入节点以上节点的平衡因子向上判断该节点是否影响上面树的平衡性// 若影响上面树的平衡性那么需要旋转来平衡树使其平衡else if (parent-_bf 1 || parent-_bf -1){if (parent _root)break;cur parent;parent parent-_parent;}else if (parent-_bf 2 || parent-_bf -2){// 右右高左单旋if (parent-_bf 2 cur-_bf 1){RotateL(parent);break;}// 左左高右单旋else if (parent-_bf -2 cur-_bf -1){RotateR(parent);break;}// 右左高右左双旋先将当前节点右单旋再将父亲节点左单旋else if (parent-_bf 2 cur-_bf -1){RotateRL(parent);break;}// 左右高左右双旋先将当前节点左单旋再将父亲节点右旋单旋else if (parent-_bf -2 cur-_bf 1){RotateLR(parent);break;}else{assert(false);}}// 当父亲节点的平衡因子为其他值时那么这棵树一定是出现了问题else{assert(false);}}return true;}void InOrder(){_InOrder(_root);}void _InOrder(Node* root){if (root nullptr)return;_InOrder(root-_left);cout root-_kv.first endl;_InOrder(root-_right);}bool IsBalance(){return _IsBalance(_root);}size_t Size(){return _Size(_root);}int Height(){return _Height(_root);}private:bool _IsBalance(Node* root){if (root nullptr)return true;bool left _IsBalance(root-_left);if (!left) return left;bool right _IsBalance(root-_right);if (!right) return right;if (_Height(root-_right) - _Height(root-_left) ! root-_bf)cout root-_kv.first : 平衡因子异常 endl;return left right abs(_Height(root-_left) - _Height(root-_right) 2);}size_t _Size(Node* root){if (root nullptr)return 0;return _Size(root-_left) _Size(root-_right) 1;}int _Height(Node* root){if (root nullptr)return 0;int left _Height(root-_left);int right _Height(root-_right);return left right ? left 1 : right 1;}// 右单旋void RotateR(Node* parent){Node* subL parent-_left;Node* subLR subL-_right;parent-_left subLR;if (subLR)subLR-_parent parent;Node* Pparent parent-_parent;subL-_right parent;parent-_parent subL;if (parent _root){_root subL;subL-_parent nullptr;}else{subL-_parent Pparent;if (Pparent-_left parent){Pparent-_left subL;}else{Pparent-_right subL;}}parent-_bf subL-_bf 0;}// 左单旋void RotateL(Node* parent){Node* subR parent-_right;Node* subRL subR-_left;parent-_right subRL;if (subRL)subRL-_parent parent;Node* Pparent parent-_parent;parent-_parent subR;subR-_left parent;if (parent _root){_root subR;subR-_parent nullptr;}else{subR-_parent Pparent;if (Pparent-_left parent){Pparent-_left subR;}else{Pparent-_right subR;}}parent-_bf subR-_bf 0;}// 左右双旋void RotateLR(Node* parent){Node* subL parent-_left;Node* subLR subL-_right;int bf subLR-_bf;RotateL(subL);RotateR(parent);if (bf 0){parent-_bf subL-_bf subLR-_bf 0;}else if (bf -1){parent-_bf 1;subL-_bf 0;subLR-_bf 0;}else if (bf 1){subL-_bf -1;parent-_bf 0;subLR-_bf 0;}}// 右左双旋void RotateRL(Node* parent){Node* subR parent-_right;Node* subRL subR-_left;int bf subRL-_bf;RotateR(subR);RotateL(parent);if (bf 0){parent-_bf subR-_bf subRL-_bf 0;}else if (bf -1){subRL-_bf 0;parent-_bf 0;subR-_bf 1;}else if (bf 1){subRL-_bf 0;parent-_bf -1;subR-_bf 0;}}Node* _root nullptr; }; 二、红黑树 2.1 红黑树的概念 红黑树是一种二叉搜索树但在每个结点上增加一个存储位表示结点的颜色可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制红黑树确保没有一条路径会比其他路径长出俩倍因而是接近平衡的。 2.2 红黑树的性质 红黑树中的根节点必定为黑色节点红黑树上的节点不是黑色节点就是红色节点红黑树中可以存在连续黑色节点但是不能出现连续红色节点红黑树中的每一条路径上的黑色节点的数目相同 思考为什么满足上面的性质红黑树就能保证其最长路径中节点个数不会超过最短路径节点个数的两倍 解答由于红黑树中的所有路径上的黑色节点数目相同红黑树中又不能出现连续的红色节点所以红色节点插入在黑色节点之间或是黑色节点的后面。最短路径的一定是路径上的所有节点都为黑色节点最长路径一定是在最短路径的基础上每两个黑色节点中插入一个红色节点再在最后一个黑色节点后面插入一个红色节点所以最长路径的节点个数不会超过最短路径的两倍。 2.3 红黑树节点的定义 enum Color {RED,BLACK };templateclass T struct RBTreeNode {RBTreeNode* _left;RBTreeNode* _right;RBTreeNode* _parent;T _date;Color _col;RBTreeNode(const T date): _right(nullptr) // 节点的右孩子, _left(nullptr) // 节点的左孩子, _parent(nullptr) // 节点的父亲, _col(RED) // 节点的颜色, _date(date) // 节点存储的内容{} };思考在节点的定义中为什么要将节点的默认颜色给成红色的 解答由于红黑树上每条路径上的黑色节点的数量是相同的插入一个节点而节点的颜色是黑色就会导致插入黑色节点的那个路径上的黑色节点的数量比其他路径上的黑色节点数量多上一个那么这颗树就会出现问题。而插入节点的颜色为红色可以出现问题就算出现问题最多就是出现连续的两个红色节点可以通过变色、旋转来解决连续红色节点的问题操作起来更加的简单。 2.4 红黑树的结构 2.5 红黑树的插入操作 红黑树是在二叉搜索树的基础上加上其平衡限制条件因此红黑树的插入可分为两步 按照二叉搜索的树规则插入新节点检测新节点插入后红黑树的性质是否造到破坏 因为新节点的默认颜色是红色因此如果其双亲节点的颜色是黑色没有违反红黑树任何性质则不需要调整但当新插入节点的双亲节点颜色为红色时就违反了性质三不能有连在一起的红色节点此时需要对红黑树分情况来讨论 约定:c为当前节点p为父节点g为祖父节点u为叔叔节点 情况一: c为红p为红g为黑u存在且为红问题c和p均为红违反了性质三此处能否将p直接改为黑 解答不可以将p直接改为黑色会使含有p节点的路径多一个黑色节点违反了每条路径有相同黑色节点数量的原则。 解决方式将p,u改为黑g改为红然后把g当成c继续向上调整。 情况二: c为红p为红g为黑u不存在/u存在且为黑说明:u的情况有两种 如果u节点不存在则c一定是新插入节点因为如果c不是新插入节点则c和p一定有一个节点的颜色是黑色就不满足性质4:每条路径黑色节点个数相同。如果u节点存在则其一定是黑色的那么c节点原来的颜色一定是黑色的现在看到其是红色的原因是因为c的子树在调整的过程中将c节点的颜色由黑色改成红色。 p为g的左孩子c为p的左孩子则进行右单旋转相反 p为g的右孩子c为p的右孩子则进行左单旋转 p、g变色–p变黑g变红 情况三: c为红p为红g为黑u不存在/u存在且为黑p为g的左孩子c为p的右孩子则针对p做左单旋转变为情况二再进行一次右单旋 p为g的右孩子c为p的左孩子则针对p做右单旋转变为情况二再进行一次左单旋。 templateclass K, class T class RBTree { public:typedef RBTreeNodeT Node;// 在红黑树中插入值为data的节点插入成功返回true否则返回false// 注意为了简单起见本次实现红黑树不存储重复性元素pairiterator,bool Insert(const T date){if (nullptr _root){_root new Node(date);_root-_col BLACK;return make_pair(iterator(_root),true);}Node* cur _root;Node* parent cur-_parent;KofT koft;while (cur){if (koft(cur-_date) koft(date)){parent cur;cur cur-_left;}else if (koft(cur-_date) koft(date)){parent cur;cur cur-_right;}else {return make_pair(iterator(cur),false);}}// 插入新节点cur new Node(date);// 由于后面cur可能会随着旋转而改变// 这里定义一个newNode记录一下Node* newNode cur;cur-_parent parent;if (koft(parent-_date) koft(date)){parent-_left cur;}else{parent-_right cur;}// 有向上处理的情况可能存在parent不存在的情况while (parent parent-_col RED){Node* grandfather parent-_parent;// g// p u// cif (parent grandfather-_left){Node* uncle grandfather-_right;// 叔叔存在且叔叔的颜色为红色// 变色完后子树的根节点为红色并且该节点的父亲节点的颜色可能为红色// 需要向上调整if (uncle uncle-_col RED){parent-_col uncle-_col BLACK;grandfather-_col RED;cur grandfather;parent cur-_parent;}// 叔叔存在且叔叔的颜色为黑色 || 叔叔不存在// 旋转完后子树的根节点为黑色不需要向上调整else{// 左左 则 右旋if (cur parent-_left){RotateR(grandfather);parent-_col BLACK;grandfather-_col RED;}// 左右 则 左右双旋else{RotateL(parent);RotateR(grandfather);grandfather-_col RED;cur-_col BLACK;}break;}}// (parent grandfather-_right)else{// g// u p// cNode* uncle grandfather-_left;// 叔叔存在且为红色// 叔叔和父亲变为黑色祖父变为红色// 由于祖父的父亲可能为红色继续向上处理if (uncle uncle-_col RED){parent-_col uncle-_col BLACK;grandfather-_col RED;cur grandfather;parent cur-_parent;}// 叔叔不存在或叔叔存在且为黑色色// 旋转处理旋转后父亲变黑祖父变红// 子树的根节点为黑色不需要继续处理else{// g// u p// cif (cur parent-_right){RotateL(grandfather);parent-_col BLACK;grandfather-_col RED;}// g// u p// celse{RotateR(parent);RotateL(grandfather);cur-_col BLACK;grandfather-_col RED;}break;}}// 将根节点变为黑色}_root-_col BLACK;return make_pair(iterator(newNode) , true);}private:// 右单旋void RotateR(Node* parent){Node* subL parent-_left;Node* subLR subL-_right;parent-_left subLR;if (subLR)subLR-_parent parent;Node* Pparent parent-_parent;subL-_right parent;parent-_parent subL;if (parent _root){_root subL;subL-_parent nullptr;}else{subL-_parent Pparent;if (Pparent-_left parent){Pparent-_left subL;}else{Pparent-_right subL;}}}// 左单旋void RotateL(Node* parent){Node* subR parent-_right;Node* subRL subR-_left;parent-_right subRL;if (subRL)subRL-_parent parent;Node* Pparent parent-_parent;parent-_parent subR;subR-_left parent;if (parent _root){_root subR;subR-_parent nullptr;}else{subR-_parent Pparent;if (Pparent-_left parent){Pparent-_left subR;}else{Pparent-_right subR;}}} private:Node* _root nullptr;size_t _size; };2.6 红黑树的验证 红黑树的检测分为两步 检测其是否满足二叉搜索树(中序遍历是否为有序序列)检测其是否满足红黑树的性质 templateclass K, class T, class KofT class RBTree { public:typedef RBTreeNodeT Node;// 检测红黑树是否为有效的红黑树注意其内部主要依靠_IsValidRBTRee函数检测bool IsValidRBTRee(){if (nullptr _root){return false;}if (_root-_col RED){return false;}int blackCount 0;Node* cur _root;while (cur){if (cur-_col BLACK){blackCount;}cur cur-_left;}return _IsValidRBTRee(_root, blackCount, 0);}// 中序遍历void InOrder(){_InOrder(_root);} private:void _InOrder(Node* pRoot){if (pRoot nullptr){return;}_InOrder(pRoot-_left);cout pRoot-_kv.first : pRoot-_kv.second endl;_InOrder(pRoot-_right);}bool _IsValidRBTRee(Node* pRoot, size_t blackCount, size_t pathBlack){// 判断是否每条路径黑色节点是否相同if (nullptr pRoot){if (blackCount ! pathBlack){cout 有路径黑色节点不相同 endl;return false;}else{return true;}}if (pRoot-_col BLACK)pathBlack;// 判断是否出现连续红色节点if (pRoot-_col RED pRoot-_parent-_col RED){cout 有连续红色节点 endl;return false;}return _IsValidRBTRee(pRoot-_left, blackCount, pathBlack) _IsValidRBTRee(pRoot-_right, blackCount, pathBlack);} private:Node* _root nullptr;size_t _size; };2.7 红黑树与AVL树的比较 红黑树和AVL树都是高效的平衡二叉树增删改查的时间复杂度都是O( l o g 2 N log_2 N log2​N)红黑树不追求绝对平衡其只需保证最长路径不超过最短路径的2倍相对而言降低了插入和旋转的次数所以在经常进行增删的结构中性能比AVL树更优而且红黑树实现比较简单所以实际运用中红黑树更多。 三、红黑树的模拟实现 3.1 红黑树中迭代器的实现 templateclass T, class Ref, class Ptr struct __TreeIterator {typedef RBTreeNodeT Node;typedef __TreeIteratorT, Ref, Ptr Self;__TreeIterator(Node* node):_node(node){}Ref operator*(){return _node-_date;}Ptr operator-(){return _node-_date;}bool operator(const Self s){return _node s._node;}bool operator!(const Self s){return _node ! s._node;}// 左子树 根 右子树// 若当前节点的右树不为空则指向当前节点的最右节点// 若当前节点右树为空则沿着这条路径向上查找// 找到孩子是父亲左的祖先使迭代器指向这个祖先Self operator(){Node* cur this-_node;if (nullptr ! cur-_right){// 指向右树cur cur-_right;// 指向右树最左节点while (cur cur-_left){cur cur-_left;}_node cur;}else{Node* parent cur-_parent;// cur为根节点时parent为空// 所以这里要判断parent是否为空while (parent cur parent-_right){cur parent;parent cur-_parent;}// 找到了cur是parent左_node parent;}return *this;}// 右子树 根 左子树// 若当前节点的左子树不为空则找到左子树的最右节点// 若当前节点的左子树为空则沿着这条路径向上查找// 找到孩子是父亲的右的祖先节点使迭代器指向这个节点Self operator--(){Node* cur _node;if (nullptr ! cur-_left){cur cur-_left;while (cur cur-_right){cur cur-_right;}_node cur;}else{Node* parent cur-parent;// cur为根节点时parent为空// 所以这里要判断parent是否为空while (parent cur parent-_left){cur parent;parent cur-_parent;}_node parent;}return *this;}private:Node* _node; };3.2 红黑树中clear、size 和 empty 的实现 templateclass K, class T, class KofT class RBTree { public:typedef RBTreeNodeT Node;bool Empty()const{return _root nullptr;}void Clear(){_Clear(_root);}size_t Size()const{return _size;} private:size_t _Size(Node* pRoot){if (pRoot nullptr){return 0;}return _Size(pRoot-_left) _Size(pRoot-_right) 1;}void _Clear(Node* pRoot){if (pRoot nullptr)return;_Clear(pRoot-_left);_Clear(pRoot-_right);delete pRoot;pRoot nullptr;} private:Node* _root nullptr;size_t _size; }; 3.3 获得红黑树中的最左/右节点 templateclass K, class T, class KofT class RBTree { public:typedef RBTreeNodeT Node;// 获取红黑树最左侧节点Node* LeftMost(){Node* cur _root;while (cur cur-_left){cur cur-_left;}return cur;}// 获取红黑树最右侧节点Node* RightMost(){Node* cur _root;while (cur cur-_right){cur cur-_right;}return cur;}private:Node* _root nullptr;size_t _size; };3.4 红黑树中 begin 和 end 的实现 templateclass K, class T, class KofT class RBTree { public:typedef RBTreeNodeT Node;typedef __TreeIteratorT, T, T* iterator;typedef __TreeIteratorT, const T, const T* const_iterator;iterator begin(){Node* cur _root;while (cur cur-_left){cur cur-_left;}return iterator(cur);}iterator end(){return iterator(nullptr);}const_iterator begin()const{Node* cur _root;while (cur cur-_left){cur cur-_left;}return const_iterator(cur);}const_iterator end()const{return const_iterator(nullptr);}private:Node* _root nullptr;size_t _size; };3.5 红黑树中 insert 的实现 这里类模版参数中的KofT是为了后面set和map封装由于插入节点时需要有元素的比较set是直接使用K直接进行比较而map是取pairK,V中的K那么两种对象比较方式不同而将insert写两遍不方便那么换一个思路那么就写一个仿函数可以让set取到Kmap取到pairK,V中的K而这个仿函数在封装set和map中写到并在创建对象时将仿函数传给KofT。 templateclass K, class T, class KofT class RBTree { public:typedef RBTreeNodeT Node;typedef __TreeIteratorT, T, T* iterator;typedef __TreeIteratorT, const T, const T* const_iterator;// 在红黑树中插入值为data的节点插入成功返回true否则返回false// 注意为了简单起见本次实现红黑树不存储重复性元素// 这里pair的返回值应该是pairiterator,bool// 但是由于set封装中的无论是iterator还是const_iterator// 实际上都是const_iterator而这里的iterator并不能用来构造const_iterator// 我们可以写一个iterator用来构造const_iterator// 但是这里为了方便就返回一个节点的指针Node*// Node* 无论是iterator还是const_iterator都能构造pairNode*, bool Insert(const T date){if (nullptr _root){_root new Node(date);_root-_col BLACK;_size;return make_pair(_root, true);}Node* cur _root;Node* parent cur-_parent;KofT koft;while (cur){if (koft(cur-_date) koft(date)){parent cur;cur cur-_left;}else if (koft(cur-_date) koft(date)){parent cur;cur cur-_right;}else{return make_pair(cur, false);}}// 插入新节点cur new Node(date);// 由于后面cur可能会随着旋转而改变// 这里定义一个newNode记录一下Node* newNode cur;cur-_parent parent;if (koft(parent-_date) koft(date)){parent-_left cur;}else{parent-_right cur;}// 有向上处理的情况可能存在parent不存在的情况while (parent parent-_col RED){Node* grandfather parent-_parent;// g// p u// cif (parent grandfather-_left){Node* uncle grandfather-_right;// 叔叔存在且叔叔的颜色为红色// 变色完后子树的根节点为红色并且该节点的父亲节点的颜色可能为红色// 需要向上调整if (uncle uncle-_col RED){parent-_col uncle-_col BLACK;grandfather-_col RED;cur grandfather;parent cur-_parent;}// 叔叔存在且叔叔的颜色为黑色 || 叔叔不存在// 旋转完后子树的根节点为黑色不需要向上调整else{// 左左 则 右旋if (cur parent-_left){RotateR(grandfather);parent-_col BLACK;grandfather-_col RED;}// 左右 则 左右双旋else{RotateL(parent);RotateR(grandfather);grandfather-_col RED;cur-_col BLACK;}break;}}// (parent grandfather-_right)else{// g// u p// cNode* uncle grandfather-_left;// 叔叔存在且为红色// 叔叔和父亲变为黑色祖父变为红色// 由于祖父的父亲可能为红色继续向上处理if (uncle uncle-_col RED){parent-_col uncle-_col BLACK;grandfather-_col RED;cur grandfather;parent cur-_parent;}// 叔叔不存在或叔叔存在且为黑色色// 旋转处理旋转后父亲变黑祖父变红// 子树的根节点为黑色不需要继续处理else{// g// u p// cif (cur parent-_right){RotateL(grandfather);parent-_col BLACK;grandfather-_col RED;}// g// u p// celse{RotateR(parent);RotateL(grandfather);cur-_col BLACK;grandfather-_col RED;}break;}}// 将根节点变为黑色}_root-_col BLACK;_size;return make_pair(newNode, true);} 在红黑树中插入值为data的节点插入成功返回true否则返回false 注意为了简单起见本次实现红黑树不存储重复性元素//pairiterator,bool Insert(const T date)//{// if (nullptr _root)// {// _root new Node(date);// _root-_col BLACK;// _size;// return make_pair(iterator(_root),true);// }// Node* cur _root;// Node* parent cur-_parent;// KofT koft;// while (cur)// {// if (koft(cur-_date) koft(date))// {// parent cur;// cur cur-_left;// }// else if (koft(cur-_date) koft(date))// {// parent cur;// cur cur-_right;// }// else // {// return make_pair(iterator(cur),false);// }// }// // 插入新节点// cur new Node(date);// // 由于后面cur可能会随着旋转而改变// // 这里定义一个newNode记录一下// Node* newNode cur;// cur-_parent parent;// if (koft(parent-_date) koft(date))// {// parent-_left cur;// }// else// {// parent-_right cur;// }// // 有向上处理的情况可能存在parent不存在的情况// while (parent parent-_col RED)// {// Node* grandfather parent-_parent;// // g// // p u// // c// if (parent grandfather-_left)// {// Node* uncle grandfather-_right;// // 叔叔存在且叔叔的颜色为红色// // 变色完后子树的根节点为红色并且该节点的父亲节点的颜色可能为红色// // 需要向上调整// if (uncle uncle-_col RED)// {// parent-_col uncle-_col BLACK;// grandfather-_col RED;// cur grandfather;// parent cur-_parent;// }// // 叔叔存在且叔叔的颜色为黑色 || 叔叔不存在// // 旋转完后子树的根节点为黑色不需要向上调整// else// {// // 左左 则 右旋// if (cur parent-_left)// {// RotateR(grandfather);// parent-_col BLACK;// grandfather-_col RED;// }// // 左右 则 左右双旋// else// {// RotateL(parent);// RotateR(grandfather);// grandfather-_col RED;// cur-_col BLACK;// }// // break;// }// }// // // // (parent grandfather-_right)// else// {// // g// // u p// // c// Node* uncle grandfather-_left;// // 叔叔存在且为红色// // 叔叔和父亲变为黑色祖父变为红色// // 由于祖父的父亲可能为红色继续向上处理// if (uncle uncle-_col RED)// {// parent-_col uncle-_col BLACK;// grandfather-_col RED;// cur grandfather;// parent cur-_parent;// }// // 叔叔不存在或叔叔存在且为黑色色// // 旋转处理旋转后父亲变黑祖父变红// // 子树的根节点为黑色不需要继续处理// else// {// // g// // u p// // c// if (cur parent-_right)// {// RotateL(grandfather);// parent-_col BLACK;// grandfather-_col RED;// }// // g// // u p// // c// else// {// RotateR(parent);// RotateL(grandfather);// cur-_col BLACK;// grandfather-_col RED;// }// // break;// }// // }// // 将根节点变为黑色// }// _size;// _root-_col BLACK;// return make_pair(iterator(newNode) , true);//}private:Node* _root nullptr;size_t _size; };3.6 红黑树中 find 的实现 templateclass K, class T, class KofT class RBTree { public:typedef RBTreeNodeT Node;typedef __TreeIteratorT, T, T* iterator;typedef __TreeIteratorT, const T, const T* const_iterator;// 检测红黑树中是否存在值为data的节点存在返回该节点的地址否则返回nullptr// Node* 无论是iterator还是const_iterator都能构造Node* Find(const K k){KofT koft;Node* cur _root;while (cur){if (koft(cur-_date) k){cur cur-_right;}else if (koft(cur-_date) k){cur cur-_left;}else{return cur;}}return nullptr;}private:Node* _root nullptr;size_t _size; };3.7 红黑树的整体实现 #pragma once #include iostream #include string #include vector#includestdlib.husing namespace std;enum Color {RED,BLACK };templateclass T struct RBTreeNode {RBTreeNode* _left;RBTreeNode* _right;RBTreeNode* _parent;T _date;Color _col;RBTreeNode(const T date): _right(nullptr), _left(nullptr), _parent(nullptr), _col(RED), _date(date){} };templateclass T, class Ref ,class Ptr struct __TreeIterator {typedef RBTreeNodeT Node;typedef __TreeIteratorT , Ref , Ptr Self;__TreeIterator(Node* node):_node(node){}Ref operator*(){return _node-_date;}Ptr operator-(){return _node-_date;}bool operator(const Self s){return _node s._node;}bool operator!(const Self s){return _node ! s._node;}// 左子树 根 右子树// 若当前节点的右树不为空则指向当前节点的最右节点// 若当前节点右树为空则沿着这条路径向上查找// 找到孩子是父亲左的祖先使迭代器指向这个祖先Self operator(){Node* cur this-_node;if (nullptr ! cur-_right){// 指向右树cur cur-_right;// 指向右树最左节点while (cur cur-_left){cur cur-_left;}_node cur;}else{Node* parent cur-_parent;// cur为根节点时parent为空// 所以这里要判断parent是否为空while (parent cur parent-_right){cur parent;parent cur-_parent;}// 找到了cur是parent左_node parent;}return *this;}// 右子树 根 左子树// 若当前节点的左子树不为空则找到左子树的最右节点// 若当前节点的左子树为空则沿着这条路径向上查找// 找到孩子是父亲的右的祖先节点使迭代器指向这个节点Self operator--(){Node* cur _node;if (nullptr ! cur-_left){cur cur-_left;while (cur cur-_right){cur cur-_right;}_node cur;}else{Node* parent cur-parent;// cur为根节点时parent为空// 所以这里要判断parent是否为空while (parent cur parent-_left){cur parent;parent cur-_parent;}_node parent;}return *this;}private:Node* _node; };templateclass K ,class T, class KofT class RBTree { public:typedef RBTreeNodeT Node;typedef __TreeIteratorT , T ,T* iterator;typedef __TreeIteratorT, const T, const T* const_iterator;// 在红黑树中插入值为data的节点插入成功返回true否则返回false// 注意为了简单起见本次实现红黑树不存储重复性元素// 这里pair的返回值应该是pairiterator,bool// 但是由于set封装中的无论是iterator还是const_iterator// 实际上都是const_iterator而这里的iterator并不能用来构造const_iterator// 我们可以写一个iterator用来构造const_iterator// 但是这里为了方便就返回一个节点的指针Node*// Node* 无论是iterator还是const_iterator都能构造pairNode*, bool Insert(const T date){if (nullptr _root){_root new Node(date);_root-_col BLACK;_size;return make_pair(_root, true);}Node* cur _root;Node* parent cur-_parent;KofT koft;while (cur){if (koft(cur-_date) koft(date)){parent cur;cur cur-_left;}else if (koft(cur-_date) koft(date)){parent cur;cur cur-_right;}else{return make_pair(cur, false);}}// 插入新节点cur new Node(date);// 由于后面cur可能会随着旋转而改变// 这里定义一个newNode记录一下Node* newNode cur;cur-_parent parent;if (koft(parent-_date) koft(date)){parent-_left cur;}else{parent-_right cur;}// 有向上处理的情况可能存在parent不存在的情况while (parent parent-_col RED){Node* grandfather parent-_parent;// g// p u// cif (parent grandfather-_left){Node* uncle grandfather-_right;// 叔叔存在且叔叔的颜色为红色// 变色完后子树的根节点为红色并且该节点的父亲节点的颜色可能为红色// 需要向上调整if (uncle uncle-_col RED){parent-_col uncle-_col BLACK;grandfather-_col RED;cur grandfather;parent cur-_parent;}// 叔叔存在且叔叔的颜色为黑色 || 叔叔不存在// 旋转完后子树的根节点为黑色不需要向上调整else{// 左左 则 右旋if (cur parent-_left){RotateR(grandfather);parent-_col BLACK;grandfather-_col RED;}// 左右 则 左右双旋else{RotateL(parent);RotateR(grandfather);grandfather-_col RED;cur-_col BLACK;}break;}}// (parent grandfather-_right)else{// g// u p// cNode* uncle grandfather-_left;// 叔叔存在且为红色// 叔叔和父亲变为黑色祖父变为红色// 由于祖父的父亲可能为红色继续向上处理if (uncle uncle-_col RED){parent-_col uncle-_col BLACK;grandfather-_col RED;cur grandfather;parent cur-_parent;}// 叔叔不存在或叔叔存在且为黑色色// 旋转处理旋转后父亲变黑祖父变红// 子树的根节点为黑色不需要继续处理else{// g// u p// cif (cur parent-_right){RotateL(grandfather);parent-_col BLACK;grandfather-_col RED;}// g// u p// celse{RotateR(parent);RotateL(grandfather);cur-_col BLACK;grandfather-_col RED;}break;}}// 将根节点变为黑色}_root-_col BLACK;_size;return make_pair(newNode, true);}iterator begin(){Node* cur _root;while (cur cur-_left){cur cur-_left;}return iterator(cur);}iterator end(){return iterator(nullptr);}const_iterator begin()const{Node* cur _root;while (cur cur-_left){cur cur-_left;}return const_iterator(cur);}const_iterator end()const{return const_iterator(nullptr);}/*const_iterator begin()const{Node* cur _root;while (cur cur-_left){cur cur-_left;}return iterator(cur);}const_iterator end()const{return iterator(nullptr);}*//*bool operator!(iterator it){return this-_node ! it-_node;}bool operator(iterator it){return this-_node it-_node;}*/// 检测红黑树中是否存在值为data的节点存在返回该节点的地址否则返回nullptr// Node* 无论是iterator还是const_iterator都能构造 Node* Find(const K k){KofT koft;Node* cur _root;while (cur){if (koft(cur-_date) k){cur cur-_right;}else if (koft(cur-_date) k){cur cur-_left;}else{return cur;}}return nullptr;}// 获取红黑树最左侧节点Node* LeftMost(){Node* cur _root;while (cur cur-_left){cur cur-_left;}return cur;}// 获取红黑树最右侧节点Node* RightMost(){Node* cur _root;while (cur cur-_right){cur cur-_right;}return cur;}// 检测红黑树是否为有效的红黑树注意其内部主要依靠_IsValidRBTRee函数检测bool IsValidRBTRee(){if (nullptr _root){return false;}if (_root-_col RED){return false;}int blackCount 0;Node* cur _root;while (cur){if (cur-_col BLACK){blackCount;}cur cur-_left;}return _IsValidRBTRee(_root, blackCount, 0);}void InOrder(){_InOrder(_root);}size_t Size()const{return _size;}size_t Height(){return _Height(_root);}bool Empty()const{return _root nullptr;}void Clear(){Destroy(_root);} private:void _InOrder(Node* pRoot){if (pRoot nullptr){return;}_InOrder(pRoot-_left);cout pRoot-_kv.first : pRoot-_kv.second endl;_InOrder(pRoot-_right);}size_t _Height(Node* pRoot){if (pRoot nullptr){return 0;}size_t HeightLeft _Height(pRoot-_left);size_t HeightRight _Height(pRoot-_right);return HeightLeft HeightRight ? HeightLeft 1 : HeightRight 1;}void Destroy(Node* pRoot){if (pRoot nullptr)return;Destroy(pRoot-_left);Destroy(pRoot-_right);delete pRoot;pRoot nullptr;}bool _IsValidRBTRee(Node* pRoot, size_t blackCount, size_t pathBlack){// 判断是否每条路径黑色节点是否相同if (nullptr pRoot){if (blackCount ! pathBlack){cout 有路径黑色节点不相同 endl;return false;}else{return true;}}if (pRoot-_col BLACK)pathBlack;// 判断是否出现连续红色节点if (pRoot-_col RED pRoot-_parent-_col RED){cout 有连续红色节点 endl;return false;}return _IsValidRBTRee(pRoot-_left, blackCount, pathBlack) _IsValidRBTRee(pRoot-_right, blackCount, pathBlack);}// 右单旋void RotateR(Node* parent){Node* subL parent-_left;Node* subLR subL-_right;parent-_left subLR;if (subLR)subLR-_parent parent;Node* Pparent parent-_parent;subL-_right parent;parent-_parent subL;if (parent _root){_root subL;subL-_parent nullptr;}else{subL-_parent Pparent;if (Pparent-_left parent){Pparent-_left subL;}else{Pparent-_right subL;}}}// 左单旋void RotateL(Node* parent){Node* subR parent-_right;Node* subRL subR-_left;parent-_right subRL;if (subRL)subRL-_parent parent;Node* Pparent parent-_parent;parent-_parent subR;subR-_left parent;if (parent _root){_root subR;subR-_parent nullptr;}else{subR-_parent Pparent;if (Pparent-_left parent){Pparent-_left subR;}else{Pparent-_right subR;}}} private:Node* _root nullptr;size_t _size; };四、set 和 map 的封装 4.1 set的封装 #pragma once#includeRBTree.hnamespace aj {templateclass Kclass set{public:struct SetKofT{const K operator()(const K k){return k;}};// 对类模板取内嵌类型加typename告诉编译器这里是类型typedef typename RBTreeK, K, SetKofT::const_iterator iterator;typedef typename RBTreeK, K, SetKofT::const_iterator const_iterator;pairiterator, bool insert(const K k){return _set.Insert(k);}size_t size()const{return _set.Size();}// 这里无论是iterator还是const_iterator// 实际上都是const_iterator// 由于set无论是const版本还是非const版本都不能进行修改// 所以这里不需要重载const版本iterator begin()const{return _set.begin();}iterator end()const{return _set.end();}/*const_iterator begin()const{return _set.begin();}const_iterator end()const{return _set.end();}*/bool operator!(iterator it){return this ! it;}bool operator(iterator it){return this it;}bool empty()const{return _set.Empty();}void clear(){_set.Clear();}iterator find(const K k){return _set.Find(k);}const_iterator find(const K k)const{return _set.Find(k);}private:RBTreeconst K, K, SetKofT _set;}; } 4.2 map的封装 #pragma once#includeRBTree.hnamespace aj {templateclass K,class Vclass map{public:struct MapKofT{const K operator()(const pairK, V k){return k.first;}};// 这里pair中的K需要加const是因为要和下面的成员变量类型相同typedef typename RBTreeK, pairconst K, V, MapKofT::iterator iterator;typedef typename RBTreeK, pairconst K, V, MapKofT::const_iterator const_iterator;pairiterator, bool insert(const pairK, V k){return _map.Insert(k);}size_t size() {return _map.Size();}iterator begin(){return _map.begin();}iterator end(){return _map.end();}const_iterator begin()const{return _map.begin();}const_iterator end()const{return _map.end();}bool operator!(iterator it){return this ! it;}bool operator(iterator it){return this it;}bool empty()const{return _map.Empty();}void clear(){_map.Clear();}iterator find(const K k){return _map.Find(k);}const_iterator find(const K k)const{return _map.Find(k);}V operator[](const K k){// 如果k在_map中存在则operator[]充当查找的作用// 如果k在_map中不存在则operator[]充当插入的作用pairiterator, bool ret _map.insert(make_pair(k,V()));return ret.first-second;}private:RBTreeK,pairconst K,V, MapKofT _map;}; }结尾 如果有什么建议和疑问或是有什么错误大家可以在评论区中提出。 希望大家以后也能和我一起进步 如果这篇文章对你有用的话希望大家给一个三连支持一下
http://www.tj-hxxt.cn/news/231471.html

相关文章:

  • 亚马逊备案网站建设网站建设包括两个方面
  • 1元购网站怎么做网站建设及推广培训班
  • 怎么样再自己的网站做二级域名wordpress怎么加幻灯片
  • 创新创业营销策略网站建设等wordpress模板自适应
  • 搜索网站怎么做dw个人网站模板下载
  • 中国知名网站排行榜ueditor wordpress 插件
  • 网站开发的关键技术与难点西安app制作公司
  • 网站建设 别墅经常用表格进行页面布局
  • 昆明市建设局官方网站贵阳网站建设哪家
  • 网站建设视频百度网盘下载江苏建设工程信息网官网入口
  • 罗湖网站建设设计精仿36氪(36kr)wordpress主题
  • 摄影网站开发背景asp php jsp网站开发
  • 杭州俄语网站建设wordpress怎么改登陆不了
  • 最便宜的重庆网站建设米拓与wordpress
  • 东莞东城网站建设公司苏州苏网建设公司在建工程
  • 中山网站设计网页游戏制作过程的
  • 帝国网站7.2 pc wap 跳转wordpress阿里百变
  • asp.net网站sql权限设置公司装修设计公司
  • 网站维护中 源码用网站做邮箱
  • 广州网站改版方案网站怎么弄缩略图上传
  • 成都市做网站公司网站建设丨找王科杰专业
  • 南通优普营销网站建设温州制作企业网站
  • 洛夕网站建设想学软件开发报什么专业
  • 如何创建一个免费的网站网站管理和维护
  • 网站公司市场营销方案页面访问升级老域名
  • 郑州网站优化服务wordpress super 缓存
  • 宁波网站建站推广wordpress如何设置404页面跳转
  • iis网站怎么做全站伪静态网页设计与网站建设在线考试石油大学
  • 网站加速代码移动网站设计心得
  • 烟台网站建设设计西安企业建站排名