C++AVL树详解

什么是AVL树

AVL树是最先发明的⾃平衡⼆叉查找树,AVL是⼀颗空树,或者具备下列性质的⼆叉搜索树:它的
左右⼦树都是AV树,且左右⼦树的⾼度差的绝对值不超过1。AVL树是⼀颗⾼度平衡搜索⼆叉树,
通过控制⾼度差去控制平衡。
简单的来说AVL树就是可以控制自身高度差的搜索二叉树

AVL树通过什么来控制平衡

AVL树实现平衡这⾥我们引⼊⼀个平衡因⼦(balance factor)的概念,每个结点都有⼀个平衡因⼦,任何
结点的平衡因⼦等于右⼦树的⾼度减去左⼦树的⾼度,也就是说任何结点的平衡因⼦等于0/1/-1,
AVL树并不是必须要平衡因⼦,但是有了平衡因⼦可以更⽅便我们去进⾏观察和控制树是否平衡,
就像⼀个指向标⼀样。通过平衡因子我们可以更加直观的去判断AVL树到底是不是平衡的

为什么要求⾼度差不超过1,⽽不是⾼度差是0呢0不是更好的平衡吗?画画图分析我们发现,不是不想这样设计,⽽是有些情况是做不到⾼度差是0的。⽐如⼀棵树是2个结点,4个结点等情况下,⾼度差最好就是1,⽆法作为⾼度差是0
我们可以来画图看看
在这里插入图片描述

AVL树整体结点数量和分布和完全⼆叉树类似,⾼度可以控制在 ,那么增删查改的效率也可
以控制在 ,相⽐⼆叉搜索树有了本质的提升。避免了像搜索二叉树出现的一些极端情况,比如说一直插入一个比根节点小的树,就一直往左边插入,这样搜索效率就会变得很差

AVL树的插入

AVL树大致可以分为一下插入过程
1.插入和搜索二叉树一样,都是通过插入节点和当前节点进行比较小的往左走,大的往右走。

  1. 新增结点以后,只会影响祖先结点的⾼度,也就是可能会影响部分祖先结点的平衡因⼦,所以更新
    从新增结点->根结点路径上的平衡因⼦,实际中最坏情况下要更新到根,有些情况更新到中间就可
    以停⽌了,具体情况我们下⾯再详细分析。

  2. 更新平衡因⼦过程中没有出现问题,则插⼊结束

  3. 更新平衡因⼦过程中出现不平衡,对不平衡⼦树旋转,旋转后本质调平衡的同时,本质降低了⼦树
    的⾼度,不会再影响上⼀层,所以插⼊结束。

平衡因子的更新

更新规则
平衡因子 = 右子树的高度-左子树的高度

只有⼦树⾼度变化才会影响当前结点平衡因⼦

插⼊结点,会增加⾼度,所以新增结点在parent的右⼦树,parent的平衡因⼦++,新增结点在
parent的左⼦树,parent平衡因⼦–

parent所在⼦树的⾼度是否变化决定了是否会继续往上更新
更新结果
这里要分三种情况
如果更新完成之后parent是0则说明更新前子树的高度是-1或者1,说明原来的子树不平衡,一边高一边低,更新后变成0说明新插入的节点插入在低的那一边,插⼊后parent所在的⼦树⾼度不变,不会
影响parent的⽗亲结点的平衡因⼦,更新结束。
在这里插入图片描述

更新后parent的平衡因⼦等于1 或 -1,更新前更新中parent的平衡因⼦变化为0->1 或者 0->-1,说
明更新前parent⼦树两边⼀样⾼,新增的插⼊结点后,parent所在的⼦树⼀边⾼⼀边低,parent所
在的⼦树符合平衡要求,但是⾼度增加了1,会影响parent的⽗亲结点的平衡因⼦,所以要继续向上
更新
在这里插入图片描述

更新后parent的平衡因⼦等于2 或 -2,更新前更新中parent的平衡因⼦变化为1->2 或者 -1->-2,说
明更新前parent⼦树⼀边⾼⼀边低,新增的插⼊结点在⾼的那边,parent所在的⼦树⾼的那边更⾼
了,破坏了平衡,parent所在的⼦树不符合平衡要求,需要旋转处理,旋转的⽬标有两个:1、把
parent⼦树旋转平衡。2、降低parent⼦树的⾼度,恢复到插⼊结点以前的⾼度。所以旋转后也不
需要继续往上更新,插⼊结束。
在这里插入图片描述
这个旋转等下会详细说明,下面来看看AVL树的插入的实现代码

AVL树的插入

在看插入之前,我们先看看AVL树的每个节点的构造

template<class key,class value>
struct avl_node
{
	int _bf;
	pair<key, value>_kv;
	avl_node<key, value>* _left;
	avl_node<key, value>* _right;
	avl_node<key, value>* _pre_node;

	avl_node(const pair<key,value>& kv)
		:_kv(kv)
		,_left(nullptr)
		,_right(nullptr)
		,_bf(0)
		,_pre_node(nullptr)
	{}
};

这里我们有三个指针,一个指向当前节点的左边,一个指向当前节点的右边,一个指向当前节点的上一个节点(父节点),然后我们用了一个pair键值对来存放key,value的值

template<class key,class value>
class AVLtree
{
	typedef avl_node<key, value> node;
public:
	AVLtree()
		:_root(nullptr)
	{}
	bool insert(const pair<key, value>& kv)
	{
		if (_root == nullptr)
		{
			_root = new node(kv);
			return true;
		}
		node* cur = _root;
		node* parent = nullptr;
		while (cur != nullptr)
		{
			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 (parent->_kv.first < kv.first)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		cur->_pre_node = parent;
		while (parent != nullptr)//回溯跟新
		{
			if (parent->_left == cur)
			{
				parent->_bf--;//插入在左边--
			}
			else
			{
				parent->_bf++;//插入在右边++
			}
			if (parent->_bf == 0)
			{
				break;
			}
			if (parent->_bf == 1 || parent->_bf == -1)//快不平衡了
			{
				cur = parent;
				parent = parent->_pre_node;
			}
			else if (parent->_bf == -2 || parent->_bf == 2)//更新节点
			{
				if (parent->_bf == -2 && cur->_bf == -1)
				{
					rotetR(parent);//这些调整下面会详细说明
				}
				else if (parent->_bf == 2 && cur->_bf == 1)
				{
					rotetL(parent);
				}
				else if (parent->_bf == 2 && cur->_bf == -1)
				{
					rotetRL(parent);
				}
				else if (parent->_bf == -2 && cur->_bf == 1)
				{
					rotetLR(parent);
				}
				else
				{
					assert(false);
				}
				break;
			}
			else
			{
				assert(false);
			}
		}
		return true;
    }

这里插入逻辑还是和搜索二叉树一样,我们依次比较大小,当找到位置的时候,就需要向上更新平衡因子
好了接下来来说说旋转

AVL树的旋转

旋转的规则

  1. 保持搜索树的规则**(这是很重要的)**

  2. 让旋转的树从不满⾜变平衡,其次降低旋转树的⾼度
    旋转总共分为四种,左单旋/右单旋/左右双旋/右左双旋。

rotetR右单旋转

首先我们来画图看看,什么情况需要进行右旋转
这里我们用a,b,c来代表一个抽象的子树,这样的好处是可以一张图片概括所有的右单旋转的所有场景

在这里插入图片描述
下面就需要开始旋转了
在这里插入图片描述
具体步骤说明
在b⼦树中插⼊⼀个新结点,导致b⼦树的⾼度从h变成h+1,不断向上更新平衡因⼦,导致10的平
衡因⼦从-1变成-2,10为根的树左右⾼度差超过1,违反平衡规则。10为根的树左边太⾼了,需要
往右边旋转,控制两棵树的平衡。

旋转核⼼步骤,因为5 < c⼦树的值 < 10,将c变成10的左⼦树,10变成5的右⼦树,5变成这棵树新
的根,符合搜索树的规则,控制了平衡,同时这棵的⾼度恢复到了插⼊之前的h+2(加2是把5和10加进去算的),符合旋转原则。如果插⼊之前10整棵树的⼀个局部⼦树,旋转后不会再影响上⼀层,插⼊结束了。
下面来带入具体的数字来说明一下
情况1插入之前 a/b/c的高度是0
在这里插入图片描述
情况2插入之前a/b/c的高度是1
在这里插入图片描述
在这里插入图片描述
好了下面我们来看看代码是怎么实现的

右旋代码

这里面其实有很多的坑,不要看着简单,实际上要注意的点有点多,首先我们需要记录三个节点第一个是subl节点(以不平衡的节点为主的左边节点),然后sublr节点也就是subl的右边节点,pparent也就是(以不平衡节点为主的上一个节点)
其实不难发现旋转时要动的节点就那三个

void rotetR(node* parent)
{
	node* subl = parent->_left;
	node* sublr = subl->_right;
	node* Pparent = parent->_pre_node;
	首先我们让parent的左边指向sublr
	parent->_left = sublr;
	为什么这里需要判断一下sublr是不是为空呢,这是因为有可能出现一种情况一直插入的
	比根小,一直往左边插入,这时候就会形成一条像”/“形状的二叉树,这时sublr是空的,所以需要判断一下
	if (sublr != nullptr)
	{
	不为空就sublr的上一个节点就是parent
		sublr->_pre_node = parent;
	}
	旋转完成之后subl就是新的根了,需要把右边->panrent
	subl->_right = parent;
	parent->_pre_node = subl;同理,向上更新
    到这里就旋转完成了
    下面就需要判断旋转的点到底是不是root节点
    
	if (parent == _root)
	{
		_root = subl;
		subl->_pre_node = nullptr;如果是就把上一个节点置为空
	}
	else
	{
	这里就体现了我们pparent的用法了
		if (Pparent->_left == parent)
		{
			Pparent->_left = subl;
		}
		else
		{
			Pparent->_right = subl;
		}
		subl->_pre_node = Pparent;
	}
	更新节点完成之后更新相应改变的平衡因子
	subl->_bf = 0;
	parent->_bf = 0;
}

这就是右旋

左旋代码

同理右旋

void rotetL(node* parent)
{
	node* subr = parent->_right;
	node* subrl = subr->_left;
	node* pparent = parent->_pre_node;

	parent->_right = subrl;
	if (subrl != nullptr)
	{
		subrl->_pre_node = parent;
	}
	subr->_left = parent;
	parent->_pre_node = subr;
	if (parent == _root)
	{
		_root = subr;
		subr->_pre_node = nullptr;
	}
	else
	{
		if (pparent->_left == parent)
		{
			pparent->_left = subr;
		}
		else
		{
			pparent->_right = subr;
		}
		subr->_pre_node = pparent;
	}
	subr->_bf = 0;
	parent->_bf = 0;
}

左右双旋

通过下面的图可以看到,左边⾼时,如果插⼊位置不是在a⼦树,⽽是插⼊在b⼦树,b⼦树⾼度从h变
成h+1,引发旋转,右单旋⽆法解决问题,右单旋后,我们的树依旧不平衡。右单旋解决的纯粹的左边
⾼,但是插⼊在b⼦树中,10为跟的⼦树不再是单纯的左边⾼,对于10是左边⾼,但是对于5是右边
⾼,需要⽤两次旋转才能解决,以5为旋转点进⾏⼀个左单旋,以10为旋转点进⾏⼀个右单旋,这棵树
这棵树就平衡了。
下面是a/b/c高度是0的情况
在这里插入图片描述
我们来看看旋转的过程
在这里插入图片描述
这样这颗树就平衡了
现在我们来看看a/b/c高度是1的情况
在这里插入图片描述
有了以上详细的例子我们来看看抽象的把a/b/c抽象成一个子树

下⾯我们将a/b/c⼦树抽象为⾼度h的AVL⼦树进⾏分析,另外我们需要把b⼦树的细节进⼀步展开为8和左⼦树⾼度为h-1的e和f⼦树,因为我们要对b的⽗亲5为旋转点进⾏左单旋,左单旋需要动b树中的左⼦树。b⼦树中新增结点的位置不同,平衡因⼦更新的细节也不同,通过观察8的平衡因⼦不同,这⾥我们要分三个场景讨论。

• 场景1:h >= 1时,新增结点插⼊在e⼦树,e⼦树⾼度从h-1变为h并不断更新8->5->10平衡因⼦,
引发旋转,其中8的平衡因⼦为-1,旋转后8和5平衡因⼦为0,10平衡因⼦为1。

• 场景2:h >= 1时,新增结点插⼊在f⼦树,f⼦树⾼度从h-1变为h并不断更新8->5->10平衡因⼦,引
发旋转,其中8的平衡因⼦为1,旋转后8和10平衡因⼦为0,5平衡因⼦为-1。

• 场景3:h == 0时,a/b/c都是空树,b⾃⼰就是⼀个新增结点,不断更新5->10平衡因⼦,引发旋
转,其中8的平衡因⼦为0,旋转后8和10和5平衡因⼦均为0。
像下面这样
在这里插入图片描述
首先我们讨论情况1
在这里插入图片描述
在这里插入图片描述
旋转完成之后,我们发现10的平衡因子是1(左边低右边高)
再来看看情况2
在这里插入图片描述
在这里插入图片描述
这时5的平衡因子是-1(右边低左边高)
最后一种情况类似于上面这种,就不做过多解释了
在这里插入图片描述

下面来看看代码

void rotetLR(node* parent)
{
	node* subl = parent->_left;
	node* sublr = subl->_right;
	int bf = sublr->_bf;
	rotetL(parent->_left);
	rotetR(parent);
	if (bf == 0)//对应第三种
	{
		parent->_bf = 0;
		subl->_bf = 0;
		sublr->_bf = 0;
	}
	else if (bf == 1)//对应第一种
	{
		subl->_bf = -1;
		parent->_bf = 0;
		sublr->_bf = 0;
	}
	else if (bf == -1)//对应第二种
	{
		parent->_bf = 1;
		subl->_bf = 0;
		sublr->_bf = 0;
	}
	else
	{
		assert(false);
	}
}

右左双旋

逻辑和上面一样

void rotetRL(node* parent)
{
	node* subr = parent->_right;
	node* subrl = subr->_left;
	int bf = subrl->_bf;
	rotetR(parent->_right);
	rotetL(parent);
	if (bf == 1)
	{
		subr->_bf = 0;
		parent->_bf = -1;
		subrl->_bf = 0;
	}
	else if (bf == -1)
	{
		parent->_bf = 0;
		subrl->_bf = 0;
		subr->_bf = 1;
	}
	else if (bf == 0)
	{
		parent->_bf = 0;
		subrl->_bf = 0;
		subr->_bf = 0;
	}
	else
	{
		assert(false);
	}
}

AVL树的中序遍历

和普通搜索二叉树一样

void _InOrder(node* root)
{
	if (root == nullptr)
	{
		return;
	}

	_InOrder(root->_left);
	cout << root->_kv.first << ":" << root->_kv.second << endl;
	_InOrder(root->_right);
}

怎么判断是不是AVL树

这里可以采用递归的方法来判断
先从根节点去递归检查高度,用高度差和平衡因子来检查,以此类推

int heigh(node* root)
{
	if (root == nullptr)
	{
		return 0;
	}
	int lef = heigh(root->_left);
	int rig = heigh(root->_right);
	return lef > rig ? lef + 1 : rig + 1;
}
bool cheak_AVL(node* root)
{
	if (root == nullptr)
	{
		return true;
	}
	int lef = heigh(root->_left);
	int rig = heigh(root->_right);
	int diff =rig-lef;
	if (abs(diff) >= 2)
	{
		printf("高度异常");
		return false;
	}
	 if (root->_bf != diff)
	{
		printf("平衡因子异常");
		return false;
	}
	return cheak_AVL(root->_left) && cheak_AVL(root->_right);
}

源码

#pragma once
#include <utility>
#include<assert.h>
# include<iostream>
using namespace std;
template<class key,class value>
struct avl_node
{
	int _bf;
	pair<key, value>_kv;
	avl_node<key, value>* _left;
	avl_node<key, value>* _right;
	avl_node<key, value>* _pre_node;

	avl_node(const pair<key,value>& kv)
		:_kv(kv)
		,_left(nullptr)
		,_right(nullptr)
		,_bf(0)
		,_pre_node(nullptr)
	{}
};
template<class key,class value>
class AVLtree
{
	typedef avl_node<key, value> node;
public:
	AVLtree()
		:_root(nullptr)
	{}
	bool insert(const pair<key, value>& kv)
	{
		if (_root == nullptr)
		{
			_root = new node(kv);
			return true;
		}
		node* cur = _root;
		node* parent = nullptr;
		while (cur != nullptr)
		{
			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 (parent->_kv.first < kv.first)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		cur->_pre_node = parent;
		while (parent != nullptr)//回溯
		{
			if (parent->_left == cur)
			{
				parent->_bf--;
			}
			else
			{
				parent->_bf++;
			}
			if (parent->_bf == 0)
			{
				break;
			}
			if (parent->_bf == 1 || parent->_bf == -1)
			{
				cur = parent;
				parent = parent->_pre_node;
			}
			else if (parent->_bf == -2 || parent->_bf == 2)//更新节点
			{
				if (parent->_bf == -2 && cur->_bf == -1)
				{
					rotetR(parent);
				}
				else if (parent->_bf == 2 && cur->_bf == 1)
				{
					rotetL(parent);
				}
				else if (parent->_bf == 2 && cur->_bf == -1)
				{
					rotetRL(parent);
				}
				else if (parent->_bf == -2 && cur->_bf == 1)
				{
					rotetLR(parent);
				}
				else
				{
					assert(false);
				}
				break;
			}
			else
			{
				assert(false);
			}
		}
		return true;
    }
	void rotetR(node* parent)
	{
		node* subl = parent->_left;
		node* sublr = subl->_right;
		node* Pparent = parent->_pre_node;
		parent->_left = sublr;
		if (sublr != nullptr)
		{
			sublr->_pre_node = parent;
		}
		subl->_right = parent;
		parent->_pre_node = subl;
		if (parent == _root)
		{
			_root = subl;
			subl->_pre_node = nullptr;
		}
		else
		{
			if (Pparent->_left == parent)
			{
				Pparent->_left = subl;
			}
			else
			{
				Pparent->_right = subl;
			}
			subl->_pre_node = Pparent;
		}
		subl->_bf = 0;
		parent->_bf = 0;
	}

	void rotetL(node* parent)
	{
		node* subr = parent->_right;
		node* subrl = subr->_left;
		node* pparent = parent->_pre_node;

		parent->_right = subrl;
		if (subrl != nullptr)
		{
			subrl->_pre_node = parent;
		}
		subr->_left = parent;
		parent->_pre_node = subr;
		if (parent == _root)
		{
			_root = subr;
			subr->_pre_node = nullptr;
		}
		else
		{
			if (pparent->_left == parent)
			{
				pparent->_left = subr;
			}
			else
			{
				pparent->_right = subr;
			}
			subr->_pre_node = pparent;
		}
		subr->_bf = 0;
		parent->_bf = 0;

	}
	void rotetLR(node* parent)
	{
		node* subl = parent->_left;
		node* sublr = subl->_right;
		int bf = sublr->_bf;
		rotetL(parent->_left);
		rotetR(parent);
		if (bf == 0)
		{
			parent->_bf = 0;
			subl->_bf = 0;
			sublr->_bf = 0;
		}
		else if (bf == 1)
		{
			subl->_bf = -1;
			parent->_bf = 0;
			sublr->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 1;
			subl->_bf = 0;
			sublr->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}
	void rotetRL(node* parent)
	{
		node* subr = parent->_right;
		node* subrl = subr->_left;
		int bf = subrl->_bf;
		rotetR(parent->_right);
		rotetL(parent);
		if (bf == 1)
		{
			subr->_bf = 0;
			parent->_bf = -1;
			subrl->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 0;
			subrl->_bf = 0;
			subr->_bf = 1;
		}
		else if (bf == 0)
		{
			parent->_bf = 0;
			subrl->_bf = 0;
			subr->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}
	void inoder()
	{
		_InOrder(_root);
	}
	bool ck()
	{
		return cheak_AVL(_root);
	}
private:
	void _InOrder(node* root)
	{
		if (root == nullptr)
		{
			return;
		}

		_InOrder(root->_left);
		cout << root->_kv.first << ":" << root->_kv.second << endl;
		_InOrder(root->_right);
	}
	int heigh(node* root)
	{
		if (root == nullptr)
		{
			return 0;
		}
		int lef = heigh(root->_left);
		int rig = heigh(root->_right);
		return lef > rig ? lef + 1 : rig + 1;
	}
	bool cheak_AVL(node* root)
	{
		if (root == nullptr)
		{
			return true;
		}
		int lef = heigh(root->_left);
		int rig = heigh(root->_right);
		int diff =rig-lef;
		if (abs(diff) >= 2)
		{
			printf("高度异常");
			return false;
		}
		 if (root->_bf != diff)
		{
			printf("平衡因子异常");
			return false;
		}
		return cheak_AVL(root->_left) && cheak_AVL(root->_right);
	}
	node* _root;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/889219.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法-依据先序遍历和中序遍历构建二叉树

简单的二叉树遍历算法&#xff0c; 为了通过给定的先序遍历&#xff08;preorder&#xff09;和中序遍历&#xff08;inorder&#xff09;数组构造二叉树&#xff0c;我们需要理解这两种遍历方式的特点&#xff1a; 先序遍历&#xff08;Preorder&#xff09;&#xff1a;首先…

网站集群批量管理-Ansible(playbook)

1.剧本概述 1. playbook 文件,用于长久保存并且实现批量管理,维护,部署的文件. 类似于脚本存放命令和变量 2. 剧本yaml格式,yaml格式的文件:空格,冒号 2. 区别 ans-playbookans ad-hoc共同点批量管理,使用模块批量管理,使用模块区别重复调用不是很方便,不容易重复场景部署服务…

网关在不同行业自动化生产线的应用

网关在不同行业自动化生产线的应用&#xff0c;展示了其作为信息与物理世界交汇点的广泛影响力&#xff0c;尤其在推动行业智能化、自动化方面发挥了不可估量的作用。以下是网关技术在污水处理、智慧农业、智慧工厂、电力改造及自动化控制等领域的深入应用剖析。 1. 污水处理 …

java方法对象案例

完成电影信息展示功能&#xff1b;根据电影id查询该电影的详细 主方法&#xff1a; package Y; import java.util.Scanner; public class 模仿电影系统main { //目标&#xff1a;完成电影信息展示功能&#xff1b;根据电影id查询该电影的详细 //电影数据// 1,"水门桥&q…

超级智能“试衣镜”!GarDiff:高保真保持目标人物特征和服装细节,虚拟试穿技术新SOTA!

今天给大家介绍一个最新的虚拟试穿技术GarDiff&#xff0c;它可以分析你想穿的衣服和你的照片并提取出衣服的颜色、纹理和形状等细节。然后通过一个特殊的“对比器”来确保衣服与您的身体形状完美契合。这个对比器会使用两种不同的“眼睛”&#xff1a;一种是可以看到整体外观的…

PhotoMaker部署文档

一、介绍 PhotoMaker&#xff1a;一种高效的、个性化的文本转图像生成方法&#xff0c;能通过堆叠 ID 嵌入自定义逼真的人类照片。相当于把一张人的照片特征提取出来&#xff0c;然后可以生成你想要的不同风格照片&#xff0c;如写真等等。 主要特点&#xff1a; 在几秒钟内…

【华为HCIP实战课程七】OSPF邻居关系排错MTU问题,网络工程师

一、MTU MUT默认1500,最大传输单元,一致性检测 [R3-GigabitEthernet0/0/1]mtu 1503//更改R3的MTU为1503 查看R3和SW1之间的OSPF邻居关系正常: 默认华为设备没有开启MTU一致性检测! [R3-GigabitEthernet0/0/1]ospf mtu-enable //手动开启MTU检测 [SW1-Vlanif30]ospf mtu…

centos7 yum仓库无法使用的问题

1、问题 如下 2、按照csdn等网页说的做了没有用&#xff01;CentOS-yum源不可用报错&#xff1a;Could not retrieve mirrorlist 问题解决_yum could not retrieve mirrorlist-CSDN博客 3、使用b站博主的方法解决&#xff01; LinuxMirrors: GNU/Linux 一键更换系统软件源脚本…

Ambari搭建Hadoop集群 — — 问题总结

Ambari搭建Hadoop集群 — — 问题总结 一、部署教程&#xff1a; 参考链接&#xff1a;基于Ambari搭建大数据分析平台-CSDN博客 二、问题总结&#xff1a; 1. VMwear Workstation 查看网关 2. 资源分配 参考&#xff1a; 硬盘&#xff1a;master&#xff08;29 GB&#xff…

基于组合模型的公交交通客流预测研究

摘 要 本研究致力于解决公交客流预测问题&#xff0c;旨在通过融合多种机器学习模型的强大能力&#xff0c;提升预测准确性&#xff0c;为城市公交系统的优化运营和交通管理提供科学依据。研究首先回顾了公交客流预测领域的相关文献&#xff0c;分析了传统统计方法在处理大规…

去噪扩散概率模型(Denoising Diffusion Probabilistic Models, DDPM)-Python案例

1、去噪概率模型&#xff08;Denoising Probabilistic Models&#xff09; 去噪概率模型&#xff08;Denoising Probabilistic Models&#xff09;是一类通过学习数据的潜在分布来去除噪声的生成模型。其核心思想是&#xff0c;在有噪声的数据中&#xff0c;模型通过条件概率学…

pytest框架之fixture测试夹具详解

前言 大家下午好呀&#xff0c;今天呢来和大家唠唠pytest中的fixtures夹具的详解&#xff0c;废话就不多说了咱们直接进入主题哈。 一、fixture的优势 ​ pytest框架的fixture测试夹具就相当于unittest框架的setup、teardown&#xff0c;但相对之下它的功能更加强大和灵活。 …

基于SSM医疗信息管理系统(源码+定制+参考)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

Python数字图像处理实战——基于OpenCV实现多种滤波器(附完整代码和结果图)

Python数字图像处理实战——基于OpenCV实现多种滤波器&#xff08;附完整代码和结果图&#xff09; 关于作者 作者&#xff1a;小白熊 作者简介&#xff1a;精通python、matlab、c#语言&#xff0c;擅长机器学习&#xff0c;深度学习&#xff0c;机器视觉&#xff0c;目标检测…

分辨率提高4到8倍!AI高清修复工具-upscayl使用方法!

你还在为手中的模糊照片苦恼吗&#xff1f; 是不是想把老照片或低分辨率的图片用于大尺寸印刷&#xff0c;却因为画质糟糕而无从下手&#xff1f; 现在你不再需要高深的Photoshop技能&#xff0c;也不用花费巨资找人修图。借助AI高清修复工具Upscayl&#xff0c;只需几秒钟&am…

Python、R语言Lasso、Ridge岭回归、XGBoost分析Airbnb房屋数据:旅游市场差异、价格预测

全文链接&#xff1a;https://tecdat.cn/?p37839 原文出处&#xff1a;拓端数据部落公众号 分析师&#xff1a; Kefan Yu 在大众旅游蓬勃发展的背景下&#xff0c;乡村旅游已成为推动乡村经济、社会和文化发展的关键力量。当前&#xff0c;乡村旅游接待设施主要以招待所、…

基于Python的抑郁症患者看护系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

如何实现Vue2项目升级Vue3?

Vue3正式版已经发布有两年多了&#xff0c;如今它也已成为Vue的默认开发版本&#xff0c;如果你想要对之前Vue2项目进行升级重构&#xff0c;可以从以下几个维度入手&#xff1a; ① 构建工具 ② 入口文件 ③ 插件 ④ 指令 ⑤ 路由 ⑥ 状态管理 ⑦ 其他 一、构建工具 Vue3推荐使…

HTB:Base[WriteUP]

目录 连接至HTB服务器并启动靶机 1.Which two TCP ports are open on the remote host? 2.What is the relative path on the webserver for the login page? 3.How many files are present in the /login directory? 4.What is the file extension of a swap file? …

springboot如何集成mybatis?

背景&#xff1a;以前一直是直接cv一个项目中现成的xml文件&#xff0c;然后再去自己配置mapper等数据。自己准备做一个单独的例子试一下。 步骤1&#xff1a;在pom.xml文件中插入mybatis-generator插件&#xff0c;这里选的版本是1.3.2&#xff0c;然后指定的generator文件是在…