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

C++ 浅谈之 AVL 树和红黑树

C++ 浅谈之 AVL 树和红黑树

HELLO,各位博友好,我是阿呆 🙈🙈🙈

这里是 C++ 浅谈系列,收录在专栏 C++ 语言中 😜😜😜

本系列阿呆将记录一些 C++ 语言重要的语法特性 🏃🏃🏃

OK,兄弟们,废话不多直接开冲 🌞🌞🌞


一 🏠 概述

AVL 树

上文提到对于二叉搜索树有单边树的缺陷,那么对于 STL 关联容器 map、set 等底层结构对其进行了平衡处理,采用平衡树实现

AVL 树,当向二叉搜索树插入新结点后,保证每个结点左右子树高度差绝对值不超过 1 ,降低树高度,减少平均搜索长度


概念

AVL 树是空树或具有如下性质的二叉搜索树

① 左右子树都是 AVL 树

② 左右子树高度之差 ( 简称平衡因子 : 右子树高 - 左子树高 ) 绝对值不超过 1

一棵二叉搜索树高度平衡,它就是 AVL 树。如果它有 n 个结点,其高度可保持在 O(log2N),搜索时间复杂度 O(log2N)


AVL 树节点定义

template<class K,class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;//定义成三叉链的形式int _bf;//balance factor平衡因子pair<K, V> _kv;//用pair同时存K和V两个数据AVLTreeNode(const pair<K,V>& kv)//节点构造函数:_left(nullptr),_right(nullptr),_parent(nullptr),_bf(0)//平衡因子初始给0,_kv(kv){}
};

AVL 树插入

AVL 树是在二叉搜索树基础上引入平衡因子,插入过程如下

① 按照二叉搜索树方式找到空位置,插入新节点

② 插入新节点后,需要调整节点的平衡因子

③ 插入元素后可能导致 AVL 树左右子树高度不符合条件,需要旋转


AVL 树旋转

AVL树的旋转分为多种,具体举出一种如下图所示(右单旋)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1k1kVipt-1676620255584)(E:\2022年MD文档\2023 年 MD文档\二月\浅谈系列\C++ 浅谈之 AVL 树和红黑树.assets\企业微信截图_16766174867883.png)]

Parent 平衡因子为 2 或 -2 ,分以下情况

① 平衡因子为 2,说明右子树高,需要往左边压高度,设 Parent 右子树根为 SubR

当 SubR 平衡因子为 1 时,执行左单旋

当 SubR 平衡因子为 -1 时,执行右左双旋

② 平衡因子为 -2,说明左子树高,需要往右边压高度,设 Parent 左子树根为 SubL

当 SubL 平衡因子为 -1 时,执行右单旋

当 SubL 平衡因子为 1 时,执行左右双旋

旋转完成后,原 Parent 为根子树个高度降低,已经平衡(无需往上更新,直接退出循环)


AVL 树模拟实现

#pragma once
#include<iostream>
#include<assert.h>
#include<string>
using namespace std;template<class K,class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;//定义成三叉链的形式int _bf;//balance factor平衡因子pair<K, V> _kv;//用pair同时存K和V两个数据AVLTreeNode(const pair<K,V>& kv)//节点构造函数:_left(nullptr),_right(nullptr),_parent(nullptr),_bf(0)//平衡因子初始给0,_kv(kv){}
};template<class K,class V>
class AVLTree
{typedef AVLTreeNode<K, V> Node;
public:AVLTree():_root(nullptr){}//拷贝构造和赋值拷贝也需要自己实现AVLTree(const AVLTree<K,V>& kv){_root = Copy(kv._root);}AVLTree<K, V>& operator=(AVLTree<K,V> kv){swap(_root, kv._root);return *this;}~AVLTree(){Destroy(_root);_root = nullptr;}Node* Copy(Node* root){if (root == nullptr)return nullptr;Node* newroot = new Node(root->_key);//建立新节点newroot->_left = Copy(root->_left);//新节点的左右节点再去转换成子问题newroot->_right = Copy(root->_right);return newroot;//最后返回新节点}void Destroy(Node* root){//利用后序遍历去释放节点if (root == nullptr){return;}Destroy(root->_left);Destroy(root->_right);delete root;}V& operator[](const K& key)//重载operator[]{//operator[]的原则是://如果插入成功返回插入都value的引用//如果插入失败则返回V类型默认缺省值pair<Node*, bool> ret = Insert(make_pair(key, V()));//V采用传匿名对象的方式return ret.first->_kv.second;}Node* Find(const pair<K, V>& kv)//查找函数{Node* cur = _root;while (cur){if (kv.first > cur->_kv.first){cur = cur->_right;}else if (kv.first < cur->_kv.first){cur = cur->_left;}else{return cur;}}return nullptr;}void RotateR(Node* parent)//右单旋{Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR != nullptr)//注意:这里一定要判断不为空的,因为下面可能会出现空指针的解引用{subLR->_parent = parent;}subL->_right = parent;Node* parentParent = parent->_parent;//一定要在改变链接关系之前把这个指针存下来parent->_parent = subL;//if (parentParent == nullptr)或者采用这个条件也是可以的if(parent==_root){_root = subL;_root->_parent = nullptr;}else{//这里注意:parent还有父母时,链接之前需要注意判断到底是右孩子还是左孩子if (parentParent->_left == parent)parentParent->_left = subL;elseparentParent->_right = subL;subL->_parent = parentParent;//最后还要把父指针关系链接上}parent->_bf = subL->_bf = 0;//最后右单旋完成后平衡因子都要修改成0}void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;//先把subR的左孩子赋值给parent的右节点parent->_right = subRL;if (subRL != nullptr)//注意一定要判断是否为空的情况{subRL->_parent = parent;//然后链接parent指针}//然后subR的左节点链接上parentsubR->_left = parent;Node* parentParent = parent->_parent;//提前记录parent->_parent = subR;//if (parentParent == nullptr)if (parent == _root){_root = subR;_root->_parent = nullptr;}else{if (parentParent->_left == parent)parentParent->_left = subR;elseparentParent->_right = subR;subR->_parent = parentParent;}parent->_bf = subR->_bf = 0;}void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;//注意:需要提前存subRL的平衡因子,因为旋转可能引起改变//subRL的平衡因子是双旋的关键节点RotateR(parent->_right);//先进行右旋,并注意旋转点为父节点的右节点RotateL(parent);//再进行左旋,此时旋转点为父节点if (bf == 0){parent->_bf = 0;subR->_bf = 0;subRL->_bf = 0;}else if (bf == 1){parent->_bf = -1;subR->_bf = 0;subRL->_bf = 0;}else if (bf == -1){parent->_bf = 0;subR->_bf = 1;subRL->_bf = 0;}//注意这里处理完成过后sunRL的平衡因子一定都是等于0的else{assert(false);}}void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;RotateL(parent->_left);//先进行左旋,并注意旋转点为父节点的左节点RotateR(parent);//再进行右旋,此时旋转点为父节点if (bf == 0){parent->_bf = 0;subL->_bf = 0;subLR->_bf = 0;}else if (bf == 1){parent->_bf = 0;subL->_bf = -1;subLR->_bf = 0;}else if (bf == -1){parent->_bf = 1;subL->_bf = 0;subLR->_bf = 0;}//注意这里处理完成过后sunRL的平衡因子一定都是等于0的else{assert(false);}}pair<Node*,bool> Insert(const pair<K, V>& kv){if (_root == nullptr)//根节点为空时先new一个新节点{_root = new Node(kv);return make_pair(_root, true);}Node* cur = _root;Node* parent = nullptr;//先利用while循环去找cur的空位while (cur){if (kv.first > cur->_kv.first){parent = cur;cur = cur->_right;}else if (kv.first < cur->_kv.first){parent = cur;cur = cur->_left;}else{return make_pair(cur, false);}}//将cur插入到相应位置cur = new Node(kv);Node* newnode = cur;//用一个newnode记录一下新节点用以返回if (kv.first > parent->_kv.first){parent->_right = cur;//注意三叉链的链接逻辑顺序,等号左右方向不能反,先把cur链接到父节点的右边cur->_parent = parent;//然后再去把父指针知道父节点}else{parent->_left = cur;cur->_parent = parent;}//进行旋转调整//while(cur!=_root)while (parent){//1.进入循环先对平衡因子进行调整if (cur == parent->_right){parent->_bf++;}else{parent->_bf--;}//分三种情况向上走if (parent->_bf == 0)//平衡因子等于0不需要调整{//为什么不需调整//因为等于0的话,说明底层子树高度不平衡,添加进入新元素后平衡了,只要平衡了高度并没发生变化,不会影响上面的父节点break;}else if (parent->_bf == -1 || parent->_bf == 1){//平衡因子等于-1,说明插入新节点后子树的高度不平衡了,需要继续往上迭代查看父节点是否还满足平衡节点cur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2){if (parent->_bf == -2)//父节点等于-2,说明左边高,触发右旋的情况{if (cur->_bf == -1)//cur节点等于-1,说明在cur的左边更高,触发右单旋的情况{RotateR(parent);}else//cur等于-1,说明在cur的右边更高,触发左右双旋{RotateLR(parent);}}else//父节点等于1,说明右边更高,触发左旋的情况{if (cur->_bf == 1)//cur节点等于1时,说明在cur的右边更高,触发右单旋的情况{RotateL(parent);}else//cur等于-1,说明在cur的左边更高,触发右左双旋{RotateRL(parent);}}//思考:为什么上面在传参数的时候,都是传parent的节点呢?这样的好处是什么呢break;//调整完成后break退出循环//这里为什么调整完成过后就可以退出,通过旋转调整平衡因子后,parent节点的平衡因子都为0了,调整过后不需要再向上继续查找了}else{assert(false);}}return make_pair(newnode,true);}void _Inorder(Node* root)//中序遍历打印每个节点{if (root == nullptr)return;_Inorder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_Inorder(root->_right);}void Inorder(){_Inorder(_root);cout << endl;}//验证是否为平衡二叉树//1.左子树高度与右子树高度差必须小于1int _Height(Node* root)//求树的高度函数{if (root == nullptr){return 0;}int leftHeight = _Height(root->_left);//递归去子问题求解int rightHeight = _Height(root->_right);return rightHeight > leftHeight ? rightHeight + 1 : leftHeight + 1;}bool _IsBalance(Node* root){if (root == nullptr){return true;}int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);// 2.检查一下每颗树的平衡因子是否正确if (rightHeight - leftHeight != root->_bf){cout << "平衡因子异常:" << root->_kv.first << endl;return false;}return abs(rightHeight - leftHeight) < 2&& _IsBalance(root->_left)&& _IsBalance(root->_right);//分别递归到各自的左右子树再去检查}bool IsAVLTree(){return _IsBalance(_root);}
private:Node* _root;
};

二 🏠 核心

红黑树

红黑树的概念

一种二叉搜索树,在每个结点上增加一个存储位表示结点颜色,Red 或 Black。确保没有一条路径会比其他路径长 2 倍,因而接近平衡


红黑树性质

红黑树的定义

  1. 每个结点不是红就是黑
  2. 根节点是黑色
  3. 一个节点是红,则两个孩子是黑 ( 没有连续红节点 )
  4. 每条路径上包含相同数量黑节点
  5. 每个叶子结点都是黑 ( 此处指的是空结点,即 NIL 节点 )

为什么红黑树能保证最长路径中节点个数不会超过最短路径的两倍 ?

假设黑节点数量 N 个,最短路径为 :logN,最长路径为 :2 * logN . 所以最长路径节点数不会超过最短路径的两倍


红黑树节点定义

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. 按照二叉搜索树规则插入新节点

  2. 检测新节点插入后,红黑树性质是否造到破坏

如果父节点是黑色(未违反红黑树任何性质),则不需要调整;

父节点为红色时,违反了定义三不能有连在一起的红色节点

此时对红黑树有多种情况,如下图为其中一种讨论

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Aai00yvJ-1676620255586)(E:\2022年MD文档\2023 年 MD文档\二月\浅谈系列\C++ 浅谈之 AVL 树和红黑树.assets\1676619846457.png)]


红黑树模拟实现

#pragma once
#include<iostream>
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;//节点中存放的T类型的数据Colour _col;//节点的颜色RBTreeNode(const pair<K,V> kv):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(kv),_col(RED){}
};template<class K,class V>
class RBTree
{typedef RBTreeNode<K, V> Node;
public:RBTree():_root(nullptr){}//拷贝构造和赋值拷贝也需要自行实现这里不做赘述~RBTree(){Destory(_root);_root = nullptr;}void Destory(Node* root){if (root == nullptr){return;}//利用后序遍历释放节点Destory(root->_left);Destory(root->_right);delete root;}void RotateR(Node* parent)//右单旋{Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR != nullptr)//注意:这里一定要判断不为空的,因为下面可能会出现空指针的解引用{subLR->_parent = parent;}subL->_right = parent;Node* parentParent = parent->_parent;//一定要在改变链接关系之前把这个指针存下来parent->_parent = subL;//if (parentParent == nullptr)或者采用这个条件也是可以的if (parent == _root){_root = subL;_root->_parent = nullptr;}else{//这里注意:parent还有父母时,链接之前需要注意判断到底是右孩子还是左孩子if (parentParent->_left == parent)parentParent->_left = subL;elseparentParent->_right = subL;subL->_parent = parentParent;//最后还要把父指针关系链接上}}void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;//先把subR的左孩子赋值给parent的右节点parent->_right = subRL;if (subRL != nullptr)//注意一定要判断是否为空的情况{subRL->_parent = parent;//然后链接parent指针}//然后subR的左节点链接上parentsubR->_left = parent;Node* parentParent = parent->_parent;//提前记录parent->_parent = subR;//if (parentParent == nullptr)if (parent == _root){_root = subR;_root->_parent = nullptr;}else{if (parentParent->_left == parent)parentParent->_left = subR;elseparentParent->_right = subR;subR->_parent = parentParent;}}pair<Node*, bool> Insert(const pair<K, V> kv){if (_root == nullptr){_root = new Node(kv);_root->_col = BLACK;//根节点给黑色return make_pair(_root, true);}Node* cur = _root;Node* parent = nullptr;while (cur)//循环去找空位{if (kv.first > cur->_kv.first){parent = cur;cur = cur->_right;}else if(kv.first < cur->_kv.first){parent = cur;cur = cur->_left;}else{return make_pair(cur, false);}}Node* newnode = new Node(kv);newnode->_col = RED;//链接上新节点if (kv.first > parent->_kv.first){parent->_right = newnode;newnode->_parent = parent;}else{parent->_left = newnode;newnode->_parent = parent;}cur = newnode;//父节点存在且父节点为红色时需要继续处理while (parent && parent->_col == RED){Node* grandfather = parent->_parent;//关键看叔叔的脸色if (parent == grandfather->_left){Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED){//具体变色的情况需要画图分析:grandfather->_col = RED;parent->_col = uncle->_col = BLACK;//注意需要继续向上处理,容易忘记cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_left){RotateR(grandfather);//右单旋parent->_col = BLACK;grandfather->_col = RED;}else{RotateL(parent);//先以父节点为旋转点左旋RotateR(grandfather);//再以g为旋转点右旋cur->_col = BLACK;grandfather->_col = RED;}break;//旋转+变色过后一定是满足所有性质的直接退出循环}}else{Node* uncle = grandfather->_left;if (uncle && uncle->_col == RED){uncle->_col = parent->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else // 情况2:+ 情况3:{if (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else // cur == parent->_left{RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return make_pair(newnode, true);}void _InOrder(Node* root)//中序遍历递归打印{if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << ":"<<root->_kv.second<<endl;_InOrder(root->_right);}void InOrder(){_InOrder(_root);cout << endl;}bool _CheckBlance(Node* root, int blackNum, int count)//balckNum相当于一个标尺,count就是用来记录每条路径的黑节点数目{if (root == nullptr)//如果root走到空节点{if (count != blackNum)//count不等于最左路径的黑色节点数{cout << "黑色节点的数量不相等" << endl;return false;//返回假}return true;//否则返回真}if (root->_col == RED && root->_parent->_col == RED){cout << "存在连续的红色节点" << endl;return false;}if (root->_col == BLACK){count++;}return _CheckBlance(root->_left, blackNum, count)&& _CheckBlance(root->_right, blackNum, count);//再递归到各子树的子问题}bool CheckBlance(){if (_root == nullptr){return true;}if (_root->_col == RED){cout << "根节点是红色的" << endl;return false;}// 找最左路径做黑色节点数量参考值int blackNum = 0;Node* left = _root;while (left){if (left->_col == BLACK){blackNum++;}left = left->_left;}int count = 0;return _CheckBlance(_root, blackNum, count);}
private:Node* _root;
};

红黑树与 AVL 树比较

都是高效平衡二叉树,增删改查时间复杂度都是 O( log2N) ,红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径 2 倍,降低了插入和旋转次数,所以在经常进行增删结构中性能比 AVL 树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多


三 🏠 结语

身处于这个浮躁的社会,却有耐心看到这里,你一定是个很厉害的人吧 👍👍👍

各位博友觉得文章有帮助的话,别忘了点赞 + 关注哦,你们的鼓励就是我最大的动力

博主还会不断更新更优质的内容,加油吧!技术人! 💪💪💪

相关文章:

C++ 浅谈之 AVL 树和红黑树

C 浅谈之 AVL 树和红黑树 HELLO&#xff0c;各位博友好&#xff0c;我是阿呆 &#x1f648;&#x1f648;&#x1f648; 这里是 C 浅谈系列&#xff0c;收录在专栏 C 语言中 &#x1f61c;&#x1f61c;&#x1f61c; 本系列阿呆将记录一些 C 语言重要的语法特性 &#x1f3…...

【Kotlin】Kotlin函数那么多,你会几个?

目录标准函数letrunwithapplyalsotakeIftakeUnlessrepeat小结作用域函数的区别作用域函数使用场景简化函数尾递归函数&#xff08;tailrec&#xff09;扩展函数高阶函数内联函数&#xff08;inline&#xff09;inlinenoinlinecrossinline匿名函数标准函数 Kotlin标准库包含几个…...

饲养员喂养动物-课后程序(JAVA基础案例教程-黑马程序员编著-第四章-课后作业)

【案例4-2】饲养员喂养动物 记得 关注&#xff0c;收藏&#xff0c;评论哦&#xff0c;作者将持续更新。。。。 【案例目标】 案例描述 饲养员在给动物喂食时&#xff0c;给不同的动物喂不同的食物&#xff0c;而且在每次喂食时&#xff0c;动物都会发出欢快的叫声。例如&…...

数据分析:消费者数据分析

数据分析&#xff1a;消费者数据分析 作者&#xff1a;AOAIYI 创作不易&#xff0c;如果觉得文章不错或能帮助到你学习&#xff0c;记得点赞收藏评论一下哦 文章目录数据分析&#xff1a;消费者数据分析一、前言二、数据准备三、数据预处理四、个体消费者分析五、用户消费行为总…...

Transformer论文阅读:ViT算法笔记

标题&#xff1a;An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale 会议&#xff1a;ICLR2021 论文地址&#xff1a;https://openreview.net/forum?idYicbFdNTTy 文章目录Abstract1 Introduction2 Related Work3 Method3.1 Vision Transformer3.2…...

Android基础练习解答【2】

文章目录一 填空题二 判断题三 选择题四 简答题一 填空题 1&#xff0e;除了开启开发者选项之外&#xff0c;还需打开手机上的 usb调试 开关&#xff0c;然后才能在手机上调试App。 2&#xff0e;App开发的两大技术路线包括 _原生开发_和混合开发。 3&#xff0e;App工程的编译…...

k8s 搭建

需求&#xff1a;搭建k8s 为后续自动部署做准备进程&#xff1a;安装至少两个ubuntu18.04系统&#xff08;一个master 一到多个 node&#xff09;每个系统上都要装上docker 和 kubernetes安装dockersudo su apt-get update#安装相关插件 apt-get install apt-transport-https c…...

安全运维之mysql基线检查

版本加固 选择稳定版本并及时更新、打补丁。 稳定版本&#xff1a;发行6-12个月以内的偶数版本。 检查方法&#xff1a; 使用sql语句:select version(); 检查结果&#xff1a; 存在问题&#xff1a;当前数据库版本较老需要更新 解决方案&#xff1a;前往http://www.mysql…...

跨境电商卖家敦煌、雅虎、乐天、亚马逊测评自养号的重要性!

作为亚马逊、敦煌、乐天、雅虎等跨境的卖家&#xff0c;这两年以来&#xff0c;面对流量越来越贵的现实&#xff0c;卖家需要更加珍惜每次访问listing页面的流量&#xff0c;把转化做好&#xff0c;把流量尽可能转化为更多的订单。 提升转化率的技巧 提升产品转化率&#xff0…...

Python 之 Matplotlib xticks 的再次说明、图形样式和子图

文章目录一. 改变 x 轴显示内容 xticks 方法再次说明1. x 轴是数值型数据2. 将 x 轴更改为字符串3. 总结二. 其他元素可视性1. 显示网格&#xff1a;plt.grid()2. plt.gca( ) 对坐标轴的操作三. plt.rcParams 设置画图的分辨率&#xff0c;大小等信息四. 图表的样式参数设置1. …...

3.InfluxDB WEB使用

结合telegraf做指标数据收集 点击 Load Data -> Telegraf 配置界面 influxDB支持在WEB-UI中生成配置文件 然后利用telegraf通过远程URL请求的方式进行获取 点击CREATE CONFIGURATION 创建telegraf配置文件 选择Bucket InfluxDB提供了很多配置好的监控模板供用户选择 可以…...

git冲突合并

一、版本说明 dev&#xff1a;本地仓库中的dev分支 master&#xff1a;本地仓库中的master分支 remotes/origin/master和origin/master&#xff1a;都是远程仓库上的master分支 二、一个解决冲突的常规流程 1、前提条件&#xff1a;不能在master分支上修改任何文件。master分支…...

项目自动化构建工具make/Makefile

目录 make/Makefile概念和关系 make/Makefie的使用 一个工程中的源文件不计数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;makefile定义了一系列的规则来指定&#xff0c;哪些文件需要先编译&#xff0c;哪些文件需要后编译&#xff0c;哪些文件需要重…...

双目客流统计方案的应用原理

双目客流统计客流摄像头采用立体视觉技术实现高度统计功能。基于视差原理。利用双镜头摄取的两幅图像的视差&#xff0c;构建三维场景&#xff0c;在检测到运动目标后。通过计算图像对应点间的位置偏差。获取目标的三维信息&#xff0c;在深度图像中对目标的检测与追踪&#xf…...

python魔术方法(二)

__getattr__() class A:def __getattr__(self,name):print(f"getting {name}")raise AttributeErroro A() print(o.test)程序调用一个对象的属性&#xff0c;当这个属性不存的时候希望程序做些什么&#xff0c;这里我们打印希望的属性&#xff0c;并且抛出异常 __…...

cmd for命令笔记

语法 help for输出如下&#xff1a; 对一组文件中的每一个文件执行某个特定命令。 FOR %variable IN (set) DO command [command-parameters] %variable 指定一个单一字母可替换的参数。 (set) 指定一个或一组文件。可以使用通配符。 command 指定对每个文件执行的命令。 c…...

4.1 Filter-policy

1. 实验目的 熟悉Filter-policy的应用场景掌握Filter-policy的配置方法2. 实验拓扑 Filter-policy实验拓扑如图4-5所示: 图4-5:Filter-policy 3. 实验步骤 (1) 网络连通性 R1的配置 <Huawei>system-vi…...

day15_常用类

今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、作业 二、代码块[了解] 三、API 四、Object 五、包装类 六、数学和随机 零、 复习昨日 抽象接口修饰符abstractinterface是不是类类接口属性正常属性没…...

【网络原理5】IP协议篇

目录 IP协议报头 4位版本号 4位首部长度 8位服务类型(TOS) 16位总长度 IP拆包 16位标识、3位标志、13位片偏移​编辑 8位生存时间(TTL) 8位协议 16位首部校验和 网络地址管理 32位源ip&32位目的ip 方案一:动态分配ip地址 方案2:NAT网络地址转换(使用一个ip代…...

Unity导出WebGL工程,并部署本地web服务器

WebGL打包 设置修改 在Build Settings->PlayerSettings->Other Settings->Rendering 将Color Space 设置为Gamma 将Lightmap Encoding 设置为NormalQuality 在Build Settings->PlayerSettings->Publishing Settings 勾选Decompression Fallback 打包 完成配…...

蓝桥杯考试总结汇总

一进考场设置devc快捷键 设置注释和取消注释快捷键设置代码自动补全快捷键开启devc调试功能&#xff0c;详细可以看怎么开调试功能https://blog.csdn.net/hz18790581821/article/details/78418648比赛过程中&#xff0c;如果不相信自己是否做对&#xff0c;没有把握的&#xf…...

备战蓝桥杯【二维前缀和】

&#x1f339;作者:云小逸 &#x1f4dd;个人主页:云小逸的主页 &#x1f4dd;Github:云小逸的Github &#x1f91f;motto:要敢于一个人默默的面对自己&#xff0c;强大自己才是核心。不要等到什么都没有了&#xff0c;才下定决心去做。种一颗树&#xff0c;最好的时间是十年前…...

阿里P6细谈Python简易接口自动化测试框架设计与实现,我直呼内行

1、开发环境 操作系统&#xff1a;Ubuntu18 开发工具&#xff1a;IDEAPyCharm插件 Python版本&#xff1a;3.6 2、用到的模块 requests&#xff1a;用于发送请求 xlrd&#xff1a;操作Excel&#xff0c;组织测试用例 smtplib&#xff0c;email&#xff1a;发送测试报告 l…...

数据库存储

RAID DSL &#xff1a; Domain Spesic Language 专用领域语言 单机存储 一切皆Key-Value 本地文件系统 一切皆文件 Ceph - 分布式存储 关系型数据库通用组件 Query Engine &#xff1a;解析query&#xff0c;生成查询计划Txn Manager &#xff1a;事务并发管理Lock Man…...

hive学习笔记

一、Hive基本概念1.1 hive是什么hive是基于hadoop的一个数仓分析工具&#xff0c;hive可以将hdfs上存储的结构化的数据&#xff0c;映射成一张表&#xff0c;然后让用户写HQL(类SQL)来分析数据tel up down 1383838438 1345 1567 138383…...

7大体系防作弊,牛客放大招了!严肃笔试客户端上线!

如果问起学生对在线笔试的印象&#xff0c;“不公平”和“不服气”占了半壁江山。学生认为很多企业的在线笔试系统并不完善。原因一&#xff0c;不能有效地规避部分学生的作弊行为&#xff1b;原因二&#xff0c;在线考试系统不稳定&#xff0c;bug频出&#xff0c;导致笔试发挥…...

R语言广义可加模型在空气环境污染方面的应用(1)

粉丝私信我希望复制一篇文章的图片&#xff0c;图片来源于文章&#xff1a;Wu C, Yan Y, Chen X, Gong J, Guo Y, Zhao Y, Yang N, Dai J, Zhang F, Xiang H. Short-term exposure to ambient air pollution and type 2 diabetes mortality: A population-based time series st…...

CSDN 编程竞赛二十九期题解

竞赛总览 CSDN 编程竞赛二十九期&#xff1a;比赛详情 (csdn.net) 竞赛题解 题目1、订班服 小A班级订班服了&#xff01;可是小A是个小糊涂鬼&#xff0c;整错了好多人的衣服的大小。小A只能自己掏钱包来补钱了。小A想知道自己至少需要买多少件衣服。 #include <cstdio…...

基于STM32采用CS创世 SD NAND(贴片SD卡)完成FATFS文件系统移植与测试

一、前言 在STM32项目开发中&#xff0c;经常会用到存储芯片存储数据。 比如&#xff1a;关机时保存机器运行过程中的状态数据&#xff0c;上电再从存储芯片里读取数据恢复&#xff1b;在存储芯片里也会存放很多资源文件。比如&#xff0c;开机音乐&#xff0c;界面上的菜单图…...

K_A12_007 基于STM32等单片机驱动AS608光学指纹识别模块 OLED0.96显示

K_A12_007 基于STM32等单片机驱动AS608光学指纹识别模块 OLED0.96显示一、资源说明二、基本参数参数引脚说明三、驱动说明对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RCAS608光学指纹模块1.2、STM32F103C8T6AS608光学指纹模块五、基础知识学习与相关资料下载六、视…...

天河网站建设哪家好/百度指数明星人气榜

1.put操作时导致多线程数据不一致 当有多个线程进行put操作时 假设现在有两个线程A跟B进行put操作&#xff0c;线程A已经计算完要放入记录的桶的索引坐标&#xff0c;但是还没有将记录插到桶里面时A的时间片就已经用完&#xff0c; 然后轮到线程B执行&#xff0c;假设B的索引坐…...

xp系统做网站服务器吗/廊坊seo网站管理

转载于:https://www.cnblogs.com/liying123/p/5291669.html...

石家庄网站建设电话/市场营销策划方案3000字

1&#xff0c;linux各个内核配置选项的含义 linux各个内核配置选项含义 2&#xff0c;make menuconfig命令的使用 Y表示加载&#xff0c;N表示不加载&#xff0c;M表示的是作为模块的方式载入内核。 3&#xff0c;以模块方式载入的时候如何动态加载 如何动态加载模块转载于:htt…...

千图网在线编辑/上海百度关键词优化公司

1:普通SQL语句可以用Exec执行 eg: Select*fromtableName Exec(select * from tableName) Execsp_executesql Nselect * from tableName--请注意字符串前一定要加N 2:字段名&#xff0c;表名&#xff0c;数据库名之类作为变量时&#xff0c;必须用动态SQL eg: declarefnamevar…...

做公司网站棋牌/免费网站的软件

--------- Lexlin 2016-6-17战国时代诸侯混战&#xff0c;群雄并起&#xff0c;各诸侯国为了各自利益&#xff0c;厉兵秣马、尔虞我诈。而一些个人为了争名逐利&#xff0c;陆续入世到这种大混战之中&#xff0c;于是各种谋略之士、舌辩之士、军事达人纷纷涌现出来&#xff…...

小程序服务器可以做网站吗/百度推广怎么看关键词排名

1.安装windows Xp mode之前需要安装KB958559补丁2.安装windows xp mode注&#xff1a;此密码为Windows XP 登陆的时候用户与密码&#xff1b;待以上完成后&#xff0c;开始打开Windows XP&#xff0c;可能需要等待几分钟时间去配置Windows XP进行Windows XP后&#xff0c;将程…...