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

昆山移动网站建设网站架构设计师月薪多少

昆山移动网站建设,网站架构设计师月薪多少,太原王建设,建设网站以后#x1f525;个人主页#xff1a; Forcible Bug Maker #x1f525;专栏#xff1a; C || 数据结构 目录 #x1f308;前言#x1f525;红黑树的概念#x1f525;手撕红黑树红黑树结点的定义红黑树主体需要实现的成员函数红黑树的插入findEmpty和Size拷贝构造析构函数和… 个人主页 Forcible Bug Maker 专栏 C || 数据结构 目录 前言红黑树的概念手撕红黑树红黑树结点的定义红黑树主体需要实现的成员函数红黑树的插入findEmpty和Size拷贝构造析构函数和clear检测是否为合法红黑树Begin和End 红黑树的迭代器接口* 解引用和 - 访问operator()operator- - ()迭代器比较相等 结语 前言 本篇博客主要内容红黑树的介绍以及底层代码逻辑和实现。 刚刚接触编程的时候就听说有的大厂HR会让手撕红黑树。心中一直对这个数据结构保持着敬畏和向往今天在将其撕出来后用本篇博客加以记录望周知。 红黑树的概念 红黑树也是一种二叉搜索树但再每个结点上增加一个存储位置表示结点的颜色可以是RED红或BLACK黑。通过对任何一条根到叶子的路径上各个结点的着色方式的限制红黑树确保没有一条路径会比其他路径长出两倍因而是接近平衡的。 一颗红黑树是具有如下性质的二叉搜索树 每个结点不是红色就是黑色根结点是黑色的如果一个结点是红色则它的两个孩子结点是黑色即不会有连续的红结点对于每个结点从该结点到其所有后代叶结点的简单路径上均包含相同数目的黑色结点每个叶子结点都是黑色的此处的叶子结点指的是空结点NIL 其中3和4是最重要的两点。 手撕红黑树 红黑树结点的定义 红黑树的结点包含四个成员变量模板类型T可以存储K或者pairK,V类型便于后期封装三个指针分别为指向左孩子结点的指针指向右孩子结点的指针指向父结点的指针最后变量_col枚举类型可以存RED和BLACK。 enum Color {RED,BLACK };templateclass T struct RBTreeNode {RBTreeNodeT(const T t): _data(t), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED){}T _data;RBTreeNodeT* _left;RBTreeNodeT* _right;RBTreeNodeT* _parent;Color _col; };红黑树主体需要实现的成员函数 // T: 可能是键值对key,value // 可能是一个key // 不论节点中存储的是key, value || key, 都是按照key来进行比较的 // KeyOfValue: 提取data中的Key templateclass K, class T, class KeyOfValue class RBTree {typedef RBTreeNodeT Node; public:typedef RBTreeIteratorT, T, T* iterator;typedef RBTreeIteratorT, const T, const T* const_iterator; public:RBTree() default;RBTree(const RBTreeK, T, KeyOfValue t);// 插入值为data的节点// 返回值含义iterator代表新插入节点 bool代表释放插入成功std::pairiterator, bool Insert(const T data);// Begin和End迭代器iterator Begin();iterator End();// 红黑树是否为空是返回true否则返回falsebool Empty()const;// 返回红黑树中有效节点的个数size_t Size()const;// 将红黑树中的有效节点删除void Clear();// 检测红黑树是否为有效的红黑树注意其内部主要依靠_IsValidRBTRee函数检测bool IsValidRBTRee()// 在红黑树中查找data存在赶回该节点对应的迭代器否则返回End()iterator Find(const T data);~RBTree(); private:Node* _root; };红黑树的插入 红黑树是在二叉搜索树的基础上加上其平衡限制条件因此红黑树的插入可分为两步 首先是按照二叉搜索树的方式插入结点检测插入结点后红黑树的性质是否遭到破坏 因为新结点的默认颜色是红色因此如果父结点的颜色是黑色就没有违反性质不需调整担当插入结点的父节点也是红色时就违反了性质3不能有连在一起的红结点此时需要对红黑树分情况讨论调整 约定cur为当前结点p为父节点g为祖父结点u为叔叔结点。 情况一cur为红p为红g为黑u存在且为红 解决方式将pu变成黑色g变成红色然后把g改成cur继续向上调整。 情况二cur为红p为红g为黑u不存在/u存在且为黑这里需要做的其实就和AVL树中的单旋很像了我们需要把u结点旋转下来以维持平衡 p为g的左孩子cur为p的左孩子进行右单旋相反p为g的右孩子cur为p的右孩子则进行左单旋。p变黑色g变红色。 情况三情况二的变体cur为红p为红g为黑u不存在/u存在且为黑其实就是双旋除了不用调整平衡因子其他的和AVL树的双旋并无差别 p为g的左孩子cur为p的右孩子则针对p做左单旋转相反p为g的右孩子cur为p的左孩子则针对p做右单旋转。然后就转换成了情况2。 针对每种情况进行相应的处理即可 // 插入值为data的节点 // 返回值含义iterator代表新插入节点 bool代表释放插入成功 std::pairiterator, bool Insert(const T data) {if (_root nullptr) {_root new Node(data);_root-_col BLACK;return std::make_pair(iterator(_root, _root), true);}KeyOfValue kov;Node* parent nullptr;Node* cur _root;while (cur) {if (kov(cur-_data) kov(data)) {parent cur;cur cur-_right;}else if (kov(cur-_data) kov(data)) {parent cur;cur cur-_left;}else return std::make_pair(iterator(cur, _root), false);}cur new Node(data);Node* InsertNode cur;if (kov(parent-_data) kov(data)) {parent-_right cur;cur-_parent parent;}else {parent-_left cur;cur-_parent parent;}while (parent parent-_col RED cur-_col RED) {Node* grandParent parent-_parent;Node* uncle nullptr;// g// p uif (grandParent-_left parent) {uncle grandParent-_right;if (uncle nullptr || uncle-_col BLACK) {if (parent-_left cur) {RotateR(grandParent);parent-_col BLACK;grandParent-_col RED;}else {RotateL(parent);RotateR(grandParent);cur-_col BLACK;grandParent-_col RED;}break;}else {parent-_col BLACK;grandParent-_col RED;uncle-_col BLACK;cur grandParent;parent grandParent-_parent;}}// g// u pelse {uncle grandParent-_left;if (uncle nullptr || uncle-_col BLACK) {if (parent-_right cur) {RotateL(grandParent);parent-_col BLACK;grandParent-_col RED;}else {RotateR(parent);RotateL(grandParent);cur-_col BLACK;grandParent-_col RED;}break;}else {parent-_col BLACK;grandParent-_col RED;uncle-_col BLACK;cur grandParent;parent grandParent-_parent;}}}_root-_col BLACK;return std::make_pair(iterator(InsertNode, _root), true); }在红黑树中由于不用调节平衡因子双旋的复杂度大大降低直接使用单旋并在插入过程中调整结点颜色即可。 旋转的具体内容在AVL树中【数据结构进阶】AVL树讲解过这里就不赘述了。 // 左单旋 void RotateL(Node* parent) {Node* subR parent-_right;Node* subRL subR-_left;Node* parentParent parent-_parent;if (subRL)subRL-_parent parent;subR-_left parent;subR-_parent parentParent;parent-_right subRL;parent-_parent subR;if (parentParent nullptr) {_root subR;}else {if (parentParent-_left parent) {parentParent-_left subR;}elseparentParent-_right subR;} }// 右单旋 void RotateR(Node* parent) {Node* subL parent-_left;Node* subLR subL-_right;Node* parentParent parent-_parent;if (subLR)subLR-_parent parent;subL-_right parent;subL-_parent parentParent;parent-_left subLR;parent-_parent subL;if (parentParent nullptr) {_root subL;}else {if (parentParent-_left parent) {parentParent-_left subL;}elseparentParent-_right subL;} }find 和二叉搜索树的查找规则相同。 // 在红黑树中查找data存在赶回该节点对应的迭代器否则返回End() iterator Find(const T data) {KeyOfValue kov;Node* cur _root;while (cur) {if (kov(cur-_data) kov(data))cur cur-_right;else if (kov(cur-_data) kov(data))cur cur-_left;else return iterator(cur, _root);}return iterator(nullptr, _root); }Empty和Size Empty接口函数用来判断树是否为空Size用来计算返回树结点的个数。 // 红黑树是否为空是返回true否则返回false bool Empty()const {return _root nullptr; } // 返回红黑树中有效节点的个数 size_t Size()const {return _Size(_root); }size_t _Size(Node* root) {return root nullptr ? 0 : _Size(root-_left) _Size(root-_right) 1; }拷贝构造 RBTree(const RBTreeK, T, KeyOfValue t) {_root _Copy(t._root); }Node* _Copy(Node* root) {if (root nullptr)return nullptr;Node* newRoot new Node(root-_data);newRoot-_left _Copy(root-_left);newRoot-_right _Copy(root-_right);return newRoot; }析构函数和clear // 将红黑树中的有效节点删除 void Clear() {_Destroy(_root);_root nullptr; }~RBTree() {_Destroy(_root);_root nullptr; }void _Destroy(Node* root) {if (root nullptr)return;_Destroy(root-_left);_Destroy(root-_right);delete root; }检测是否为合法红黑树 在IsValidRBTRee中首先算出一条路径上的黑结点个数digit_black然后在每条路径递归到空结点时判断黑结点个数是否相等即可验证性质4所有路径上黑结点个数相等递归的过程中判断当前结点和父节点的颜色是否同时为红即可验证性质3没有连续的红结点 // 检测红黑树是否为有效的红黑树注意其内部主要依靠_IsValidRBTRee函数检测 bool IsValidRBTRee() {if (_root nullptr)return true;Node* cur _root;size_t digit_black 0;while (cur) {if (cur-_col BLACK)digit_black;cur cur-_left;}return _IsValidRBTRee(_root, digit_black, 0); }bool _IsValidRBTRee(Node* pRoot, size_t blackCount, size_t pathBlack) {if (pRoot nullptr) {if (blackCount pathBlack)return true;else return false;}if (pRoot-_col RED pRoot-_parent-_col RED) {return false;}if (pRoot-_col BLACK) {return _IsValidRBTRee(pRoot-_left, blackCount, pathBlack 1) _IsValidRBTRee(pRoot-_right, blackCount, pathBlack 1);}else {return _IsValidRBTRee(pRoot-_left, blackCount, pathBlack) _IsValidRBTRee(pRoot-_right, blackCount, pathBlack);} }Begin和End 这两个函数用于获取红黑树的头对象和尾迭代器。 // Begin和End迭代器 iterator Begin() {return iterator(_LeftMost(), _root); } iterator End() {return iterator(nullptr, _root); }// 获取红黑树最左侧节点 Node* _LeftMost() {if (_root nullptr)return nullptr;Node* parent _root;Node* cur parent-_left;while (cur) {parent cur;cur cur-_left;}return parent; }红黑树的迭代器接口 迭代器的好处是可以方便遍历使数据结构的底层实现变的透明从而降低代码编写的复杂程度。 templateclass T, class Ref, class Ptr struct RBTreeIterator {typedef RBTreeNodeT Node;typedef RBTreeIteratorT, Ref, Ptr Self;RBTreeIterator(Node* pNode,Node* root): _pNode(pNode),_root(root){}// 让迭代器具有类似指针的行为Ref operator*();Ptr operator-();// 然迭代器可以移动前置/后置 Self operator();Self operator(int);// 然迭代器可以移动前置/后置-- Self operator--();Self operator--(int);// 让迭代器可以比较bool operator!(const Self s)const;bool operator(const Self s)const;private:Node* _pNode;Node* _root; };* 解引用和 - 访问 // 让迭代器具有类似指针的行为 Ref operator*() {return _pNode-_data; } Ptr operator-() {return (_pNode-_data); }operator() 二叉树的中序遍历并不难实现但是要实现从任意一个结点按中序遍历跑到下一个结点这就有相当难度了。 具体逻辑为 右子树不为空访问右子树的最左结点。右子树为空代表当前结点所在子树访问完了沿着到根节点的路线孩子是父亲左的那个祖先结点就是下一个要访问的结点。 // 迭代器可以移动前置/后置 Self operator() {if (_pNode-_right) {_pNode _pNode-_right;while (_pNode-_left) _pNode _pNode-_left;}else {Node* cur _pNode;Node* parent cur-_parent;while (parent cur parent-_right) {cur parent;parent parent-_parent;}_pNode parent;}return *this; }Self operator(int) {Node* rem _pNode;if (_pNode-_right) {_pNode _pNode-_right;while (_pNode-_left)_pNode _pNode-_left;}else {Node* cur _pNode;Node* parent cur-_parent;while (parent cur parent-_right) {cur parent;parent parent-_parent;}_pNode parent;}return Self(rem); }operator- - () 这时候要判断当前迭代器是否指向尾End()同时判断树是否为空这就要用到传入迭代器对象中的_root了。在找到End()的前一个结点之后按照和operator()相反的逻辑即可实现operator--()。 具体逻辑为 左子树不为空访问左子树的最右结点。左子树为空代表当前结点所在子树访问完了沿着到根结点的路线孩子是父亲右的那个祖先结点就是下一个要访问的结点。 // 迭代器可以移动前置/后置-- Self operator--() {if (_pNode nullptr) {if (_root nullptr)assert(false);Node* parent _root;Node* cur parent-_right;while (cur) {parent cur;cur cur-_right;}_pNode parent;return *this;}if (_pNode-_left) {_pNode _pNode-_left;while (_pNode-_right)_pNode _pNode-_right;}else {Node* cur _pNode;Node* parent cur-_parent;while (parent cur parent-_left) {cur parent;parent-_parent;}_pNode parent;}return *this; }Self operator--(int) {if (_pNode nullptr) {if (_root nullptr)assert(false);Node* parent _root;Node* cur parent-_right;while (cur) {parent cur;cur cur-_right;}_pNode parent;return Self(nullptr);}Node* rem _pNode;if (_pNode-_left) {_pNode _pNode-_left;while (_pNode-_right)_pNode _pNode-_right;}else {Node* cur _pNode;Node* parent cur-_parent;while (parent cur parent-_left) {cur parent;parent-_parent;}_pNode parent;}return Self(rem); }迭代器比较相等 底层就是用指针作比较。 // 让迭代器可以比较 bool operator!(const Self s)const {return _pNode ! s._pNode; }bool operator(const Self s)const {return _pNode s._pNode; }结语 红黑树和AVL树都是高效的平衡二叉树增删改查的时间复杂度都是O( l o g 2 N log_2 N log2​N)红黑树不追求绝对平衡其只需保证最长路径不超过最短路径的2倍相对而言降低了插入和旋转的次数所以在经常进行增删的结构中性能比AVL树更优而且红黑树实现比较简单所以实际运用中红黑树更多。 红黑树的底层实现到这里就要结束了本篇的数据结构较为复杂模板的使用也有很多容易出错的点需要多加体会。感谢大家的支持♥
http://www.dnsts.com.cn/news/132095.html

相关文章:

  • 六色网站中国空间站最新消息新闻
  • 做微商去哪个网站推广社区电商平台排行榜
  • 做一个静态网站要多少钱夺宝网站建设
  • 南宁东凯做网站的公司wordpress添加悬浮按钮
  • 福建网站建建设房屋装修效果图用什么软件
  • 门户网站如何做seo如何将模板导入wordpress
  • 天台县网站建设哪家好游戏网站哪个好
  • 微网站建设哪家好网站开发qq群
  • 深圳网络开发公司有哪些做搜狗手机网站优化软
  • 帮忙做快站旅游网站辽宁建设工程信息网ca锁激活
  • 电子商务网站的设计与实现Asp网站开发入门
  • 网站的上传与发布wordpress android开源
  • 最牛视频网站建设做网站的热门行业
  • 运城手机网站制作普陀营销型网站建设
  • 网站建设和教学设计模板
  • 网站左侧导航代码手机网站字体大小规范
  • 网络营销策划书 范例seosem有什么区别
  • 黑河市网站建设公司深圳今天新闻头条
  • 网站制作用的软件有哪些做网站需要学jsp
  • linux做网站教程游戏开发公司排名
  • 西安建网站网站推广网站设计技术公司
  • asp网站关键字天津网站建设报价
  • 电子商务网站建设 代码简洁的门户网站
  • 罗湖商城网站设计费用广州推神网络科技有限公司
  • 土特产网站平台建设摄像网站建设
  • 网站建设费用还是网络专业珠海门户网站建设价格
  • 湛江cms模板建站网站系统管理计划
  • 百度推广自己做网站吗有网站公司源码可以重建网站吗
  • 做pc端网站要成本么太原百度搜索排名优化
  • 赣州网站制作公司网络推广可做哪些方面