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

空间站免费版下载如何seo推广

空间站免费版下载,如何seo推广,做毕业论文的网站,做任务兼职赚钱的网站目录 一、红黑树的概念二、红黑树的性质三、红黑树的节点的定义四、红黑树结构五、红黑树的插入操作参考代码 五、代码汇总 一、红黑树的概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过…

目录

  • 一、红黑树的概念
  • 二、红黑树的性质
  • 三、红黑树的节点的定义
  • 四、红黑树结构
  • 五、红黑树的插入操作
    • 参考代码
  • 五、代码汇总

一、红黑树的概念

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路
径会比其他路径长出俩倍,因而是接近平衡的。如图所示:
在这里插入图片描述

二、红黑树的性质

  1. 每个结点不是红色就是黑色。
  2. 根节点是黑色的。
  3. 如果一个节点是红色的,则它的两个孩子结点是黑色的。
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点。
  5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)。

问题:为什么满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍?

因为根节点是黑色是固定的,并且不能有连续的红色节点,每条路径黑色节点的个数一样,也就是说最短路就是全黑,最长路径就是一黑一红相间,所以一条路径的红色节点要么和黑色节点一样多,要么少于黑色节点,即同一条路径黑色节点的占比是大于等于50%的,所以最长路径一定不超过最短路径的2倍。

三、红黑树的节点的定义

	//通过枚举定义红色和黑色的常量enum Colour{RED,BLACK};template <class K,class V>struct RBTreeNode{public://红黑树存放的值pair<K, V> _kv;//节点的三叉链指针RBTreeNode<K,V>* _left;RBTreeNode<K,V>* _right;RBTreeNode<K,V>* _parent;//节点的颜色Colour _col;//构造函数RBTreeNode(const pair<K, V>& kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED){}};

思考:在节点的定义中,为什么要将节点的默认颜色给成红色的?
这个问题就是关于插入节点的时候我们默认插入的是黑色的节点还是红色的节点了,根据红黑树的规则,每一条路径的黑色节点的个数是一样的,假如我们插入黑色节点,那么某条路径的黑色节点就多了一个,也就是说其它路径的黑色节点也要增加一个,但是我们只插入了一个节点,要令其它路径的黑色节点的数量都增加一个,这个操作的难度显然是很大的,但是如果我们默认插入一个红色节点,那么我们最多违反了根节点为黑色或者连续两个红色节点的规则,主要还是容易违反连续两个红色节点的规则,这个问题只会影响当前节点到祖先这条路径,不会影响其他路径的节点,所以处理起来会更简洁一些,所以我们默认插入的节点是红色的。

四、红黑树结构

在这里插入图片描述

五、红黑树的插入操作

红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:

  1. 按照二叉搜索树的规则插入新节点。
  2. 检测新节点插入后,红黑树的性质是否遭到破坏,如果是,就要通过变色加旋转操作维持红黑树的性质。

因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何性质,则不需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连在一起的红色节点,此时需要对红黑树分情况来讨论:

约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点。

情况一: cur为红,p为红,g为黑,u存在且为红。
在这里插入图片描述
情况二: cur为红,p为红,g为黑,u不存在/u存在且为黑。
因为旋转后需要把p变成黑色,所以p节点和p的父节点不能再出现连续两个红色节点,所以旋转+变色后就不用再沿祖先路径更新了。

在这里插入图片描述
情况一:
在这里插入图片描述
情况二:
在这里插入图片描述
情况三:
在这里插入图片描述
情况四:
在这里插入图片描述

参考代码

		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 (kv.first < cur->_kv.first){parent = cur;cur = cur->_left;}else if (kv.first > cur->_kv.first){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(kv);if (kv.first < parent->_kv.first){parent->_left = cur;cur->_parent = parent;}else if (kv.first > parent->_kv.first){parent->_right = cur;cur->_parent = parent;}//走到这里已经插入完成,后面是检查新插入的节点有没有破坏红黑树的规则的逻辑//检查新插入的节点是否满足红黑树的规则,如果不满足就要进行变色/变色+旋转//因为新插入的cur节点的颜色一定是红色的,当cur的父节点存在并且为红色//时说明出现了连续的两个红色节点,这时需要进行变色/变色+旋转,如果父节点// 不存在或者存在且为黑色时就无需再处理了。// 为什么父节点有可能不存在?因为这是一个循环,循环更新往祖先处理可能到达根节点,//到了根节点就无需再处理了while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){Node* uncle = grandfather->_right;if (cur == parent->_left){//             grandfather//     parent//cur//画图//叔叔存在且为红if (uncle && uncle->_col == RED){//变色parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;//继续沿祖先路径检查cur = grandfather;parent = cur->_parent;//这里曾经漏写了}//叔叔不存在或者存在且为黑else//(uncle==nullptr||uncle->_col==BLACK){//单纯的左边高,进行右单旋+变色RotateR(grandfather);grandfather->_col = RED;parent->_col = BLACK;//旋转完之后无需再沿祖先路径处理break;}}else//cur == parent->_right{//              grandfather//       parent//              cur//画图//叔叔存在且为红if (uncle && uncle->_col == RED){//变色parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;//继续往上调整cur = grandfather;parent = cur->_parent;//这里曾经忘记写}//叔叔不存在或者存在且为黑else//(uncle==nullptr || uncle->_col == BLACK){//左右双旋RotateL(parent);RotateR(grandfather);//变色grandfather->_col = RED;cur->_col = BLACK;//旋转后就无需再沿祖先路径检查了,具体原因画图理解break;}}}else//(parent == grandfather->_right){Node* uncle = grandfather->_left;if (cur == parent->_right){//          grandfather//                         parent//                                    cur//画图//叔叔存在且为红if (uncle && uncle->_col == RED){//变色parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;//继续沿祖先路径检查cur = grandfather;parent = cur->_parent;}//叔叔不存在或者存在且为黑else//(uncle==nullptr || uncle->_col == BLACK){//单纯的右边高,进行左单旋+变色RotateL(grandfather);grandfather->_col = RED;parent->_col = BLACK;//旋转+变色后就不需要再沿祖先路径检查了break;}}else//(cur == parent->_left){//          grandfather//                          parent//          cur//叔叔存在且为红if (uncle && uncle->_col == RED){//变色parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;//继续沿祖先路径检查cur = grandfather;parent = cur->_parent;}//叔叔不存在或者存在且为黑else//(uncle==nullptr || uncle->_col == BLACK){//根据模型可知需要右左双旋+变色RotateR(parent);RotateL(grandfather);grandfather->_col = RED;cur->_col = BLACK;//旋转后就不需要再沿祖先路径检查了break;}}}}_num++;//最后记得把根节点的颜色改成黑色_root->_col = BLACK;return true;}//旋转的细节如果不清楚的话请看上一篇关于AVL树的旋转,红黑树的旋转和AVL树的旋转是一样的void RotateL(Node* parent){assert(parent);Node* cur = parent->_right;Node* curleft = cur->_left;Node* parentParent = parent->_parent;parent->_right = curleft;cur->_left = parent;if (curleft){curleft->_parent = parent;}parent->_parent = cur;if (parent == _root){_root = cur;cur->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = cur;}else{parentParent->_right = cur;}cur->_parent = parentParent;}}void RotateR(Node* parent){assert(parent);Node* cur = parent->_left;Node* curright = cur->_right;Node* parentParent = parent->_parent;parent->_left = curright;cur->_right = parent;if (curright){curright->_parent = parent;}parent->_parent = cur;if (parent == _root){_root = cur;cur->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = cur;}else{parentParent->_right = cur;}cur->_parent = parentParent;}}

五、代码汇总

#pragma once#include <iostream>
using namespace std;
#include <assert.h>namespace kb
{enum Colour{RED,BLACK};template <class K,class V>struct RBTreeNode{public://红黑树存放的值pair<K, V> _kv;//节点的三叉链指针RBTreeNode<K,V>* _left;RBTreeNode<K,V>* _right;RBTreeNode<K,V>* _parent;//节点的颜色Colour _col;//构造函数RBTreeNode(const pair<K, V>& kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED){}};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* parent = nullptr;Node* cur = _root;while (cur){if (kv.first < cur->_kv.first){parent = cur;cur = cur->_left;}else if (kv.first > cur->_kv.first){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(kv);if (kv.first < parent->_kv.first){parent->_left = cur;cur->_parent = parent;}else if (kv.first > parent->_kv.first){parent->_right = cur;cur->_parent = parent;}//走到这里已经插入完成,后面是检查新插入的节点有没有破坏红黑树的规则的逻辑//检查新插入的节点是否满足红黑树的规则,如果不满足就要进行变色/变色+旋转//因为新插入的cur节点的颜色一定是红色的,当cur的父节点存在并且为红色//时说明出现了连续的两个红色节点,这时需要进行变色/变色+旋转,如果父节点// 不存在或者存在且为黑色时就无需再处理了。// 为什么父节点有可能不存在?因为这是一个循环,循环更新往祖先处理可能到达根节点,//到了根节点就无需再处理了while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){Node* uncle = grandfather->_right;if (cur == parent->_left){//             grandfather//     parent//cur//画图//叔叔存在且为红if (uncle && uncle->_col == RED){//变色parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;//继续沿祖先路径检查cur = grandfather;parent = cur->_parent;//这里曾经漏写了}//叔叔不存在或者存在且为黑else//(uncle==nullptr||uncle->_col==BLACK){//单纯的左边高,进行右单旋+变色RotateR(grandfather);grandfather->_col = RED;parent->_col = BLACK;//旋转完之后无需再沿祖先路径处理break;}}else//cur == parent->_right{//              grandfather//       parent//              cur//画图//叔叔存在且为红if (uncle && uncle->_col == RED){//变色parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;//继续往上调整cur = grandfather;parent = cur->_parent;//这里曾经忘记写}//叔叔不存在或者存在且为黑else//(uncle==nullptr || uncle->_col == BLACK){//左右双旋RotateL(parent);RotateR(grandfather);//变色grandfather->_col = RED;cur->_col = BLACK;//旋转后就无需再沿祖先路径检查了,具体原因画图理解break;}}}else//(parent == grandfather->_right){Node* uncle = grandfather->_left;if (cur == parent->_right){//          grandfather//                         parent//                                    cur//画图//叔叔存在且为红if (uncle && uncle->_col == RED){//变色parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;//继续沿祖先路径检查cur = grandfather;parent = cur->_parent;}//叔叔不存在或者存在且为黑else//(uncle==nullptr || uncle->_col == BLACK){//单纯的右边高,进行左单旋+变色RotateL(grandfather);grandfather->_col = RED;parent->_col = BLACK;//旋转+变色后就不需要再沿祖先路径检查了break;}}else//(cur == parent->_left){//          grandfather//                          parent//          cur//叔叔存在且为红if (uncle && uncle->_col == RED){//变色parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;//继续沿祖先路径检查cur = grandfather;parent = cur->_parent;}//叔叔不存在或者存在且为黑else//(uncle==nullptr || uncle->_col == BLACK){//根据模型可知需要右左双旋+变色RotateR(parent);RotateL(grandfather);grandfather->_col = RED;cur->_col = BLACK;//旋转后就不需要再沿祖先路径检查了break;}}}}_num++;//最后记得把根节点的颜色改成黑色_root->_col = BLACK;return true;}size_t Size(){return _num;}bool Isbalance(){return _Isbalance(_root);}void Inorder(){_Inorder(_root);}private:bool CheckColour(Node* root, int blackNum, int BenchMark){//走到空树说明这条路径已经走完了,需要检查黑色节点的个数和基准值相不相等if (root == nullptr){//如果不相等,证明不平衡,返回falseif (blackNum != BenchMark){return false;}//如果相等,则说明本条路径没有出事,还要检查其它路径return true;}//如果出现连续红色节点证明这棵树出问题了,返回falseif (root->_col == RED && root->_parent && root->_parent->_col == RED){return false;}if (root->_col == BLACK){blackNum++;}//递归检查所有路径的颜色return CheckColour(root->_left, blackNum, BenchMark)&& CheckColour(root->_right, blackNum, BenchMark);}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);}void _Inorder(Node* root){if (root == nullptr){return;}_Inorder(root->_left);cout << root->_kv.second << " ";_Inorder(root->_right);}//旋转的细节如果不清楚的话请看上一篇关于AVL树的旋转,红黑树的旋转和AVL树的旋转是一样的void RotateL(Node* parent){assert(parent);Node* cur = parent->_right;Node* curleft = cur->_left;Node* parentParent = parent->_parent;parent->_right = curleft;cur->_left = parent;if (curleft){curleft->_parent = parent;}parent->_parent = cur;if (parent == _root){_root = cur;cur->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = cur;}else{parentParent->_right = cur;}cur->_parent = parentParent;}}void RotateR(Node* parent){assert(parent);Node* cur = parent->_left;Node* curright = cur->_right;Node* parentParent = parent->_parent;parent->_left = curright;cur->_right = parent;if (curright){curright->_parent = parent;}parent->_parent = cur;if (parent == _root){_root = cur;cur->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = cur;}else{parentParent->_right = cur;}cur->_parent = parentParent;}}private:Node* _root = nullptr;int _num = 0;//统计树的节点个数};void testRBTree(void){RBTree<int, int> rbt;int arr[]= { 16, 3, 7, 11, 9, 26, 18, 14, 15 };for (const auto& e : arr){rbt.Insert(make_pair(e, e));}/*rbt.Inorder();*/cout << rbt.Size() << endl;bool ret = rbt.Isbalance();cout << ret << endl;cout << endl;}void testRBTree1(void){RBTree<int, int> rbt;int N = 10000;srand((unsigned int)time(nullptr));for (size_t i=0;i<N;i++){int e = rand();rbt.Insert(make_pair(e, e));}cout << rbt.Size() << endl;bool ret = rbt.Isbalance();cout << ret << endl;cout << "插入完成" << endl;}
}

以上就是红黑树的相关内容了,最重要的是要理解当红黑树插入元素后违反了红黑树的规则时该如何对节点进行旋转加变色来使这棵红黑树重新回到平衡的。至于删除节点的操作就不实现了,有兴趣的可以去看看《算法导论》这本书,里面有讲红黑树删除操作的。

好啦,以上就是今天想要跟大家谈的关于红黑树的最重要的内容了,你学会了吗?如果你感觉到有所帮助,那么点点小心心,点点关注呗,后期还会持续更新C++的相关知识哦,我们下期见啦!!!


文章转载自:
http://dinncotaxonomy.bkqw.cn
http://dinncogilet.bkqw.cn
http://dinncopatristic.bkqw.cn
http://dinncolek.bkqw.cn
http://dinncohyalinization.bkqw.cn
http://dinncobullace.bkqw.cn
http://dinncosncf.bkqw.cn
http://dinncoinfill.bkqw.cn
http://dinncomillyum.bkqw.cn
http://dinncocabochon.bkqw.cn
http://dinncodisembogue.bkqw.cn
http://dinncocherubim.bkqw.cn
http://dinncoexochorion.bkqw.cn
http://dinncowatering.bkqw.cn
http://dinncocyprinoid.bkqw.cn
http://dinncozussmanite.bkqw.cn
http://dinncobidding.bkqw.cn
http://dinncomfa.bkqw.cn
http://dinncoindication.bkqw.cn
http://dinnconouny.bkqw.cn
http://dinnconecktie.bkqw.cn
http://dinncoassign.bkqw.cn
http://dinncoretributive.bkqw.cn
http://dinncolangobard.bkqw.cn
http://dinncovariolite.bkqw.cn
http://dinncojunk.bkqw.cn
http://dinncotroilism.bkqw.cn
http://dinncokidskin.bkqw.cn
http://dinncodecastylos.bkqw.cn
http://dinncomelaena.bkqw.cn
http://dinncocapetown.bkqw.cn
http://dinncocringingly.bkqw.cn
http://dinncofulgurate.bkqw.cn
http://dinnconephritogenic.bkqw.cn
http://dinncopyromagnetic.bkqw.cn
http://dinncoredye.bkqw.cn
http://dinncoincessancy.bkqw.cn
http://dinncoflopover.bkqw.cn
http://dinncoplanes.bkqw.cn
http://dinncovizard.bkqw.cn
http://dinncoltjg.bkqw.cn
http://dinncoyawny.bkqw.cn
http://dinncobyname.bkqw.cn
http://dinncodoctorand.bkqw.cn
http://dinncointerfere.bkqw.cn
http://dinncorunout.bkqw.cn
http://dinncoorogeny.bkqw.cn
http://dinncopinnate.bkqw.cn
http://dinncoisoteniscope.bkqw.cn
http://dinncoleaderless.bkqw.cn
http://dinncodesulphurize.bkqw.cn
http://dinncohaymarket.bkqw.cn
http://dinncoroughshod.bkqw.cn
http://dinncocybraian.bkqw.cn
http://dinncoentity.bkqw.cn
http://dinncojasmine.bkqw.cn
http://dinncopooch.bkqw.cn
http://dinncobloodline.bkqw.cn
http://dinncomoko.bkqw.cn
http://dinncoprogressivism.bkqw.cn
http://dinncopotboiler.bkqw.cn
http://dinncohurry.bkqw.cn
http://dinncoprejudgment.bkqw.cn
http://dinncorynd.bkqw.cn
http://dinncopenninite.bkqw.cn
http://dinncobrage.bkqw.cn
http://dinncoseparable.bkqw.cn
http://dinncodilatancy.bkqw.cn
http://dinncojacquard.bkqw.cn
http://dinncovapour.bkqw.cn
http://dinncocaravaggesque.bkqw.cn
http://dinncocommons.bkqw.cn
http://dinncouniquely.bkqw.cn
http://dinncoboz.bkqw.cn
http://dinncotelemicroscope.bkqw.cn
http://dinncoionophone.bkqw.cn
http://dinncomarginalize.bkqw.cn
http://dinncobrunizem.bkqw.cn
http://dinncocoxsackie.bkqw.cn
http://dinncoshinguard.bkqw.cn
http://dinncofdr.bkqw.cn
http://dinncounpleasing.bkqw.cn
http://dinncosexpartite.bkqw.cn
http://dinncocantonal.bkqw.cn
http://dinncosoed.bkqw.cn
http://dinncoseroot.bkqw.cn
http://dinncomalaita.bkqw.cn
http://dinncotainture.bkqw.cn
http://dinncountwist.bkqw.cn
http://dinncogiftware.bkqw.cn
http://dinncospermatologist.bkqw.cn
http://dinncomunicipalise.bkqw.cn
http://dinncostatistically.bkqw.cn
http://dinncotitillation.bkqw.cn
http://dinncoapogeotropism.bkqw.cn
http://dinncopropound.bkqw.cn
http://dinncopreparental.bkqw.cn
http://dinncopyrite.bkqw.cn
http://dinncoradioulnar.bkqw.cn
http://dinncorevisal.bkqw.cn
http://www.dinnco.com/news/134143.html

相关文章:

  • 查做空运磁检的网站seo霸屏软件
  • 如何做网站图标常见的网络营销平台有哪些
  • 做甜品网站栏目emlog友情链接代码
  • 网站设计模板百度云简述网络营销的主要方法
  • 设置本机外网ip做网站1688官网入口
  • 做电影网站会不会侵权武汉seo优化公司
  • 企业展厅设计公司豆河镇展厅设计公司笔中展览如何优化关键词搜索排名
  • 网站优化排名怎么做学历提升
  • 网站押金收回怎么做分录互联网营销师培训费用是多少
  • 外国网站做b2b的专业营销团队外包公司
  • 手机可以访问的网站怎么做网络销售 市场推广
  • 广州哪里有做网站seo zac
  • 中山做百度网站的公司吗盘古百晋广告营销是干嘛
  • wnmp搭建后怎么做网站爱客crm
  • 邵阳网站建设的话术网店推广费用多少钱
  • 高端的响应式网站建设公司网络销售怎么做才能做好
  • 宿迁做网站的公司对搜索引擎优化的认识
  • 网站建设公司彩铃注册google账号
  • 法律问题咨询哪个网站做的好cpa游戏推广联盟
  • 宁波人流哪家医院好郑州seo排名优化
  • 安徽易企建站24小时人工在线客服
  • 怎样做教育视频网站网站展示型推广
  • 经营性网站备案信息查询百度大数据官网
  • 电子商务网站建设实训过程seo词库排行
  • 南京栖霞区有做网站的吗网站seo优化公司
  • 网站建设怎么说服客户浏览器观看b站视频的最佳设置
  • 做转录组kog网站seo关键词分类
  • 旅游网站开发百度无广告搜索引擎
  • 淘宝优惠券怎么做网站今日疫情最新情况
  • 什么是网站备案熊猫关键词工具