【高阶数据结构】AVL树(动图详解)

news2024/11/13 9:33:10

🌈欢迎来到数据结构专栏~~AVL树详解


  • (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是Scort
  • 目前状态:大三非科班啃C++中
  • 🌍博客主页:张小姐的猫~江湖背景
  • 快上车🚘,握好方向盘跟我有一起打天下嘞!
  • 送给自己的一句鸡汤🤔:
  • 🔥真正的大师永远怀着一颗学徒的心
  • 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏
  • 🎉🎉欢迎持续关注!
    请添加图片描述

请添加图片描述

文章目录

  • 🌈欢迎来到数据结构专栏~~AVL树详解
    • 一. AVL树的概念
    • 二. AVL树结点的定义
    • 三. AVL树的插入
    • 四. AVL树的旋转
      • 🥑左单旋
      • 🥑右单旋(和左单旋高度相似)
      • 🔥左右单旋
      • 🔥右左单旋
    • 五. 验证AVL树
    • 六. AVL树的性能

请添加图片描述

一. AVL树的概念

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下

因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度

一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:

  • 它的左右子树都是AVL树
  • 左右子树高度之差(简称 平衡因子)的绝对值不超过1(-1/0/1)
  • 平衡因子= 右子树高度 - 左子树高度;非必须,也可以不要,只是方便我们实现的一种方式!

在这里插入图片描述
如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在
O ( l o g 2 n ) O(log_2 n) O(log2n),搜索时间复杂度O( l o g 2 n log_2 n log2n)

单支树的效率是 O ( N ) O(N) O(N)AVL树不一样,在10亿中只用找30次(可能多一点)

在这里插入图片描述

二. AVL树结点的定义

此处我们定义成三叉链结构 ,方便后序的操作;也在每个节点引入了平衡因子(右子树高度-左子树高度),还需要实现一下构造函数,左右子树以及父节点都是空,再把平衡因子设置为0即可

template<class K, class V>
struct AVLTreeNode
{
	//定义三叉链
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;
	 
	//存储的键值对
	pair<K, V> _kv;

	//平衡因子(balance factor)
	int _bf;

	//构造函数
	AVLTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_kv(kv)
		,_bf(0)
	{}
};

注意:平衡因子不是必须的,只是我们实现高度平衡的一种方式,不用平衡因子也是可以实现的

三. AVL树的插入

插入节点有三个步骤

  1. 按照二叉搜索树的原理,找到待插入的位置
  2. 判断待插入的节点是在parent的左还是右,插入节点
  3. 更新平衡因子,如果发现不平衡,则要旋转

🔥因为AVL树本身就是一颗二叉搜索树,插入规则(比较节点大小即可):

  • 插入的节点key值 > 当前位置的key值,插入到右子树
  • 插入的节点key值 < 当前位置的key值,插入到左子树
  • 插入的节点key值等于当前位置的key值,插入失败

🌈那判断完插入成功与否,是不是就要判断平衡因子的更新了

平衡因子是否更新取决于:该结点的左右子树的高度是否发生了变化,因此插入一个结点后,该结点的 祖先结点的平衡因子可能需要更新

在这里插入图片描述

🌏更新平衡因子的规则:

  • 新增在右,parent -> bf++;新增在左,parent -> bf --

每更新完一个结点的平衡因子后,都需要进行以下判断:

  1. 如果parent的平衡因子等于-1或者1,表明还需要继续往上更新平衡因子
  2. 如果parent的平衡因子等于0;表明无需往上更新平衡因子
  3. 如果parent的平衡因子等于-2或者2;就已经不平衡了,需要旋转处理
  4. 如果parent的平衡因子大于2或者小于-2;就说明之前插入的就不是AVL树了,赶紧去检查💥
更新后的平衡因子分析
-1 or 1说明parent插入前的平衡因子是0;左右子树高度相等,插入后有一边高,parent高度变了,则需要往上继续更新
0说明parent插入前的平衡因子是 -1 or 1;左右子树一边高一边低,插入后两边相等,插入的填上了矮的那一边,parent的高度不变,不需要继续往上更新
-2 or 2说明parent插入前的平衡因子是 -1 or 1;已经是平衡的临界值了;插入后变成-2 or 2 ;打破了平衡,parent所在的子树需要旋转处理

最坏的情况如下:一路更新到root根节点

在这里插入图片描述

那么我们更新平衡因子时第一个更新的就是parent结点的平衡因子,更新完parent结点的平衡因子后,若是需要继续往上进行平衡因子的更新,向上递归,直到parent为空的情况,以下逻辑是必须的

	cur = parent;
	parent = parent->_parent; 

当平衡因子出现了2/-2的情况,要对子树进行旋转处理,但也要遵守原则

  • 旋转成平衡树
  • 保持搜索树的规则

而旋转有四种大情况,对此我们要进行分类:

  1. 当parent的平衡因子为2,cur的平衡因子为1时,进行左单旋

  2. 当parent的平衡因子为-2,cur的平衡因子为-1时,进行右单旋

  3. 当parent的平衡因子为-2,cur的平衡因子为1时,进行左右双旋

  4. 当parent的平衡因子为2,cur的平衡因子为-1时,进行右左双旋

注意:旋转过后无需再往上更新平衡因子了,因为高度已经没有发生变化了,也就不会影响父节点的平衡因子了

	//插入
	bool Insert(const pair<K, 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)//插入节点值大于当前节点的key
			{
				parent = cur;
				cur = cur->_right;//往右走
			}
			else if (cur->_kv.first > kv.first)//插入节点值小于当前节点的key
			{
				parent = cur;
				cur = cur->_left;//往左走
			}
			else
			{
				//插入的节点key值等于当前位置的key值,插入失败
				return false;
			}
		}
		//开始插入
		cur = new Node(kv);
		if (parent->_kv.first < kv.first)
		{
			parent->_right = cur;
		}
		else if (parent->_kv.first < kv.first)
		{
			parent->_left = cur;
		}

		//连接parent
		cur->_parent = parent;

		//控制平衡
		//1、更新平衡因子

		while (parent)
		{
			if (cur == parent->right)
			{
				parent->_bf++;
			}
			else
			{
				parent->_bf--;
			}

			if (parent->_bf == -1 || parent->_bf == 1)//也可以用abs
			{
				cur = parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == 0)
			{
				break;
			}
			else if (parent->_bf == -2 || parent->_bf == 2)
			{
				//说明parent所在的子树已经不平衡了,需要旋转
				if (parent->_bf == 2 && cur->_bf == 1)
				{
					RotateL(parent);//左单旋
				}
				else if (parent->_bf == -2 && cur->_bf == -1)
				{
					RotateR(parent);//右单旋
				}
				else if (parent->_bf == -2 && cur->_bf == 1)
				{
					RotateLR(parent);//左右双旋
				}

				break;
			}
			else
			{
				assert(false);//在插入前树的平衡因子就有问题
			}
		}
		return true;
	}

四. AVL树的旋转

🥑左单旋

新节点插入较高右子树的右侧—右右:左单旋

⚡动图展示:

请添加图片描述

抽象图过程解析:

在这里插入图片描述
其中h可以等于0、1、2等等,不过都可以归纳到这种大情况,处理情况都一样,都是引发parent 等于2,cur等于1

左单旋旋转步骤:

  1. subRL变成parent的右子树(subL和parent的关系,要注意🔥subL可能为空
  2. parent成为subR的左子树(parent和subLR的关系)
  3. subR成为根节点(ppNode 和 subL关系,也要注意🔥parent是子树的根还是整棵树的根
  4. 最后更新平衡因子

在这里插入图片描述

为什么要这样旋转?要符合二叉搜索树规则

  • subR的左子树的值本身就比parent的值要大,所以可以作为parent的右子树
  • parent及其左子树当中结点的值本身就比subR的值小,所以可以作为subR的左子树

平衡因子更新:

在这里插入图片描述

可以看见,左单旋后树的高度就平衡了,也就无需继续向上更新平衡因子了

代码实现如下:(详细注释)

	void RotateL(Node* parent)
	{
	    //三叉链
		Node* subR = parent->_right;
		Node* subLR = subR->_left;
		Node* ppNode = parent->_parent;

		//subR 和 parent之间的关系
		subR->_left = parent;
		parent->_parent = subR;

		//subRL 和 parent之间的关系
		subRL = parent->_right;
		if (subRL)
			subRL->parent = parent;

		//ppNode 和 subR的关系
		if (ppNode == nullptr)
		{
			_root = subR;
			subR->_parent = nullptr;//没有父节点,所以为空
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subR;
			}
			else
			{
				ppNode->_right = subR;
			}
			subR->_parent = ppNode;
		}
		
		//更新平衡因子
		subR->_bf = parent->_bf = 0;
	}

🥑右单旋(和左单旋高度相似)

新节点插入较高左子树的左侧—左左:右单旋

动图演示:

请添加图片描述抽象图过程解析:

在这里插入图片描述

右单旋旋转步骤:

与左单旋雷同,看上面就行

同样也要满足二叉搜索树的性质:也是和左单旋雷同,看上面就行

平衡因子更新如下:

在这里插入图片描述同样右单旋后,parent的平衡因子为0,左右子树高度相等,也就无需继续往上更新平衡因子了

话不多说上代码:

//右单旋
void RotateR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	Node* ppNode = parent->_parent;

	//subL 和 parent的关系
	subL->_right = parent;
	parent->_parent = subL;

	//subLR 和 parent之间的关系
	parent->_left = subLR;
	if (subLR)
		subLR->_parent = parent;

	//ppNode 和 subL的关系
	if (ppNode == nullptr)
	{
		_root = subL;
		subL->_parent = nullptr;
	}
	else
	{
		if (ppNode->_left == parent)
		{
			ppNode->_left == subL;
		}
		else
		{
			ppNode->_right == subL;
		}
		subL->_parent = ppNode;
	}
		
	//更新平衡因子
	subL->_bf = parent->_bf = 0;
}

🔥左右单旋

新节点插入较高左子树的右侧—左右:先左单旋再右单旋

动图演示:
请添加图片描述

在b树或者c树中新增节点,均会引发左右双旋

旋转示意图如下:

1、插入新节点
在这里插入图片描述

2、以30为旋转点进行左单旋

在这里插入图片描述

3、以90为旋转点进行右单旋

在这里插入图片描述

左右单旋的步骤如下:

  1. 以subL为节点左单旋
  2. 以parent为节点右单旋
  3. 更新平衡因子(这才是重点)

左右双旋后满足二叉搜索树的性质:

实际上就是把subLR的左子树和右子树,分别作为subL和parent的右子树和左子树,再让subL和parent分别作为subLR的左右子树,最后让subLR作为整个子树的根(看图理解)

  • subLR左子树的节点值比subL的值大,所以可以作为subL的右子树
  • subLR右子树的节点值比parent的值小,因此可以作为parent的左子树
  • 前两个步骤之后,subL以及子树的值,和parent的值均符合,所以可以当subLR的左右子树

重点来了:(以subLR为突破口
左右双旋后,平衡因子的更新随着subLR原始平衡因子的不同分为以下三种情况:

  1. 当subLR原始平衡因子是-1时,左右双旋后parent、subL、subLR的平衡因子分别更新为1、0、0

在这里插入图片描述

  1. 当subLR原始平衡因子是1时,左右双旋后parent、subL、subLR的平衡因子分别更新为0、-1、0

在这里插入图片描述

  1. 当subLR原始平衡因子是0时,左右双旋后parent、subL、subLR的平衡因子分别更新为0、0、0

在这里插入图片描述
经过左右双旋后,即树的高度没有发生变化,所以无需继续往上更新平衡因子

话不多说,代码实现一下吧:

	void RotateLR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		int bf = subLR->_bf;

		//subL节点左单旋
		RotateL(subL);

		//parent节点进行右单旋
		RotateR(parent);

		//更新平衡因子
		if (bf == 1)
		{
			subLR->_bf = 0;
			subL->_bf = -1;
			parent->_bf = 0;
		}
		else if (bf == -1)
		{
			subLR->_bf = 0;
			subL->_bf = 0;
			parent->_bf = 1;
		}
		else if(bf == 0)
		{
			subLR->_bf = 0;
			subL->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			assert(false);//旋转前的平衡因子就出错了
		}
	}

🔥右左单旋

动图演示:

请添加图片描述

旋转图演示过程:

1、插入新节点

在这里插入图片描述

2、以subR的节点进行右单旋

在这里插入图片描述

3、以parent的节点进行右单旋

在这里插入图片描述

旋转步骤和左右双旋雷同

重点来了:(以subRL为突破口
左右双旋后,平衡因子的更新随着subRL 原始平衡因子的不同分为三种情况分别对应subRL = 0、1、2情况,此处就不多赘述了,详细可以浏览左右双旋的,情况一样

代码实现

void RotateRL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		int bf = subRL->_bf;

		//subR右单旋
		RotateR(subR);

		//parent进行左单旋
		RotateL(parent);

		if (bf == 1)
		{
			subRL->_bf = 0;
			subR->_bf = 0;
			parent->_bf = -1;
		}
		else if (bf == -1)
		{
			subRL->_bf = 0;
			subR->_bf = 1;
			parent->_bf = 0;
		}
		else if (bf == 0)
		{
			subRL->_bf = 0;
			subR->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}

五. 验证AVL树

AVL树是在二叉搜索树的基础上加入了平衡性的限制,因此要验证AVL树,可以分两步:

  1. 验证其为二叉搜索树
    如果中序遍历可得到一个有序的序列,就说明为二叉搜索树
  2. 验证其为平衡树
    • 每个节点子树高度差的绝对值不超过1(注意节点中如果没有平衡因子)
    • 节点的平衡因子是否计算正确

先验证是否为二叉搜索树

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


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

但中序遍历只能代表是二叉搜索树,不能代表是AVL树,为此还需要验证二叉树的平衡性,查平衡因子有一种监守自盗的感觉,因为平衡因子我们刚修改完,所以我们去查高度俩判断!

  • 如果是空树,证明平衡,是AVL树
  • 根高度差不大于2,并且递归子树的高度差都不大于2,即是AVL树
  • 特殊情况,平衡因子和该点的高度差对不上,要判断一下
	//是否平衡
	bool IsBalance(Node* root)
	{
		if (root == nullptr)
		{
			return true;
		}

		int leftHT = Height(root->_left);
		int rightHT = Height(root->_right);
		int diff = rightHT - leftHT;
		
		if (diff ! = root->_bf)
		{
			cout << root->_kv.first << "平衡因子异常" << endl;
			return false;
		}

		//小于2就为真 并且递归调用子树判断是否平衡
		return abs(diff) < 2
			&& _IsBalance(root->_left)
			&& _IsBalance(root->_right);
	}

	//后序查找
	int Height(Node* root)
	{
		if (root == nullptr)
			return 0;

		int leftHT = Height(root->_left);
		int rightHT = Height(root->_right);

		return max(leftHT, rightHT) + 1;
	}

六. AVL树的性能

AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间复杂度,即 l o g 2 ( N ) log_2 (N) log2(N)。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5G NR 标准 第12章 波束管理

第12章 波束管理 第 11 章一般性地讨论了多天线传输&#xff0c;然后重点介绍了多天线预编码。 讨论多天线预编码的一般假设是可以对不同的天线元件进行详细控制&#xff0c;包括相位调整和幅度缩放。 实际上&#xff0c;这需要在数模转换之前在数字域中执行发射机侧的多天线…

path 路径模块

1、什么是 path 路径模块 path 模块是 Node.js 官方提供的、用来处理路径的模块。它提供了一系列的方法和属性&#xff0c;用来满足用户对路径的处理需求。 方法名 说明 path.join() 用来将多个路径片段拼接成一个完整的路径字符串 path.basename() 用来从路径字符串中…

Kubernetes(4)- 数据存储

第八章 数据存储 ​ 在前面已经提到&#xff0c;容器的生命周期可能很短&#xff0c;会被频繁地创建和销毁。那么容器在销毁时&#xff0c;保存在容器中的数据也会被清除。这种结果对用户来说&#xff0c;在某些情况下是不乐意看到的。为了持久化保存容器的数据&#xff0c;ku…

【Java 数据结构】常见排序算法(下)

目录 1、上期回顾 2、冒泡排序 3、快速排序 3.1 理解快速排序的二叉树结构 3.2 Hoare 法 3.3 三数取中 3.4 小区间优化 3.5 挖坑法 3.6 前后指针法 3.7 注意事项 4、归并排序 1、上期回顾 上期我们主要介绍了排序的基本认识&#xff0c;以及四个排序&#xff0c;分…

【Nginx】静态资源部署(上)

文章目录Nginx静态资源概述Nginx静态资源的配置指令listen指令server_name指令匹配执行顺序location指令设置请求资源的目录root / aliasindex指令error_page指令静态资源优化配置语法Nginx静态资源压缩Gzip模块配置指令Gzip压缩功能的实例配置Gzip和sendfile共存问题gzip_stat…

116.(leaflet之家)leaflet空间判断-点与多边形的空间关系

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYPE html> <html>

电脑怎么录屏?这三个简单的电脑录屏方法,不要错过

在现在的社会&#xff0c;电脑已经是我们日常工作中不可或缺的一部分。我们通常都要在电脑进行各种各样的操作&#xff0c;所以在向其他人展示电脑操作的时候&#xff0c;我们通常都会把整个操作过程录屏下来。那电脑怎么录屏&#xff0c;今天小编就给大家分享三个简单的电脑录…

分布式数据库中间件Sharding-JDBC介绍

前文中介绍了分布式数据库中间件Mycat的一些特性&#xff0c;作为对比本文简要介绍Sharding-JDBC的一些特性以及分片的实现原理&#xff0c;进行对比分析以了解。 1、ShardingSphere介绍 ShardingSphere是一套开源的分布式数据库中间件解决方案&#xff0c;目前由Sharding-JDB…

15个有用的JavaScript技巧

今天这篇文章&#xff0c;是我从网络上整理的一些常见的 JavaScript Tips。我在我的项目中使用了所有这些实用技巧&#xff0c;今天我想把它们分享给你&#xff0c;希望也能够帮助到你。 1.数字分隔符 为了提高数字的可读性&#xff0c;可以使用下划线作为分隔符。 const la…

pytorch学习记录

pytorch学习记录0.引言1.numpy 简单入门1.1.常用基础1.2.numpy其他学习2.pytorch 简单入门2.1.Pytorch的基本组成元素2.2.Pytorch构建神经网络2.3.进阶部分2.4.其他参考资料0.引言 一步一步积累吧。 一篇不错的博客 1.numpy 简单入门 1.1.常用基础 numpy中文手册 numpy官方…

【李宏毅】HW12

HW12一、作业描述1、Policy Gradient2、Actor-Critic二、实验1、simple2、medium3、strong三、代码一、作业描述 在这个HW中&#xff0c;你可以自己实现一些深度强化学习方法&#xff1a; 1、策略梯度Policy Gradient 2、Actor-Critic 这个HW的环境是OpenAI gym的月球着陆器。…

ubuntu | 重装ubuntu(VMware虚拟机环境)

前言 最近又把双系统的ubuntu搞崩了&#xff0c;在grub界面进不去&#xff0c;估计找不到启动项&#xff0c;被迫重装。 这次觉得还是windows系统好使&#xff0c;就用vmware虚拟机了。 一、安装vmware虚拟机 参考我之前的博客。 二、安装ubuntu 下载ubuntu18.04的iso文件…

15.2 浏览器中的进程

浏览器中的进程 start 上一篇文章&#xff0c;学习到了如何区分进程和线程。在这里再复习一下&#xff0c;进程类似于一个工厂&#xff0c;线程类似于工厂的工人&#xff0c;一个工厂可以有一个或多个工人。 1. 浏览器的进程 一个浏览器中有很多的进程&#xff0c;我以谷歌…

2023年的摸鱼小技巧:Python自动生成请假条【思路详解】

嗨害大家好鸭&#xff01;我是小熊猫~ 这不2023到了&#xff0c;新的一年&#xff0c;新的摸鱼 在办公室里的小透明来实现用Python来批量生成请假条&#xff0c; 这波啊&#xff0c;这波是智取&#xff01;&#xff01;&#xff01; Python资料电子书:点击此处跳转文末名片获…

Excel函数公式大全—SUMIF/SUMIFS函数

EXCEL系列文章目录 Excel系列文章是本人亲身经历职场之后萌发的想法&#xff0c;为什么Excel覆盖如此之广&#xff0c;几乎每个公司、学校、家庭都在使用&#xff0c;但是它深藏的宝藏功能却很少被人使用&#xff0c;PQ、BI这些功能同样适用于数据分析&#xff1b;并且在一些需…

内部成员之五:内部类

文章目录一、内部类分类&#xff1a;成员内部类vs局部内部类成员内部类实例化成员内部类每日一考一、内部类 1、Java中允许将类A声明在类B中&#xff0c;则类A就是内部类&#xff0c;类B为外部类。 分类&#xff1a;成员内部类vs局部内部类 成员内部类&#xff08;静态、非静…

【ElasticSearch7.X】学习笔记(三)

【ElasticSearch7.X】学习笔记五、集群部署5.1、相关概念5.1.1、集群 Cluster3.1.2、节点 Node5.2、下载安装5.3、 启动5.4、 测试六、进阶6.1、核心概念6.1.1、索引&#xff08;Index&#xff09;6.1.2、类型&#xff08;Type&#xff09;6.1.3、文档&#xff08;Document&…

Handler的学习

一、Handler到底有什么用呢&#xff1f; 首先看以下案例&#xff1a; public class MainActivity extends AppCompatActivity { Button btn;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activi…

vue这些原理你都知道吗?(面试版)

前言 在之前面试的时候我自己也经常会遇到一些vue原理的问题, 我也总结了下自己的经常的用到的,方便自己学习,今天也给大家分享出来, 欢迎大家一起学习交流, 有更好的方法欢迎评论区指出, 后序我也将持续整理总结~ 描述 Vue 与 React 区别 说明概念: vue:是一套用于构建用户…

虚拟化技术学习笔记3

1、KVM虚拟机管理工具部署 学习目标&#xff1a; 能够为KVM虚拟机管理工具部署准备环境 能够部署KVM虚拟机管理工具 1、KVM系统需求&#xff1a; 1&#xff09;Host system requirements: 1核心、2G内存、6G硬盘 2&#xff09;KVM hypervisor requirements&#xff1a; l…