c++(AVL树及其实现)

news2024/11/17 9:56:43

一、AVL树的概念

AVL树是最先发明的自平衡⼆叉查找树,AVL是⼀颗空树,或者具备下列性质的⼆叉搜索树:它的

左右子树都是AV树,且左右子树的高度差的绝对值不超过1。AVL树是⼀颗高度平衡搜索⼆叉树,

通过控制高度差去控制平衡。

AVL树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis是两个前苏联的科学家,他们在1962

年的论文《An algorithm for the organization of information》中发表了它。

AVL树实现这里我们引入⼀个平衡因子(balance factor)的概念,每个结点都有⼀个平衡因子,任何

结点的平衡因子等于右子树的高度减去左子树的高度,也就是说任何结点的平衡因子等于0/1/-1,

AVL树并不是必须要平衡因子,但是有了平衡因子可以更方便我们去进行观察和控制树是否平衡,

就像⼀个风向标⼀样。

思考⼀下为什么AVL树是高度平衡搜索⼆叉树,要求高度差不超过1,而不是高度差是0呢?0不是更

好的平衡吗?画画图分析我们发现,不是不想这样设计,而是有些情况是做不到高度差是0的。⽐

如⼀棵树是2个结点,4个结点等情况下,高度差最好就是1,无法作为高度差是0

AVL树整体结点数量和分布和完全⼆叉树类似,高度可以控制在 ,那么增删查改的效率也可

以控制在 ,相比⼆叉搜索树有了本质的提升。

在这里插入图片描述

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

二、AVL树的实现

1、AVL树的结构

#pragma once
#include<iostream>
using namespace std;
template<class K, class V>
struct AVLTreeNode
{
	// 需要parent指针,后续更新平衡因子可以看到
	pair<K, V> _kv;
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;
	int _bf; // balance factor
	AVLTreeNode(const pair<K, V>& kv)
		:_kv(kv)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _bf(0)
	{}
};
template<class K, class V>
class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
private:
	Node * _root = nullptr;
};

2、插入

  1. 插入一个值按⼆叉搜索树规则进行插入。

  2. 新增结点以后,只会影响祖先结点的高度,也就是可能会影响部分祖先结点的平衡因子,所以更新

从新增结点->根结点路径上的平衡因子,实际中最坏情况下要更新到根,有些情况更新到中间就可

以停止了,具体情况我们下面再详细分析。

  1. 更新平衡因子过程中没有出现问题,则插入结束

  2. 更新平衡因子过程中出现不平衡,对不平衡子树旋转,旋转后本质调平衡的同时,本质降低了子树

的高度,不会再影响上⼀层,所以插入结束。

3、平衡因子更新

更新原则

平衡因子 = 右子树高度-左子树高度

只有子树高度变化才会影响当前结点平衡因子。

插入结点,会增加高度,所以新增结点在parent的右子树,parent的平衡因子++,新增结点在

parent的左子树,parent平衡因子–

parent所在子树的高度是否变化决定了是否会继续往上更新

更新停止条件:

更新后parent的平衡因子等于0,更新中parent的平衡因子变化为-1->0 或者 1->0,说明更新前

parent子树⼀边高⼀边低,新增的结点插入在低的那边,插入后parent所在的子树高度不变,不会

影响parent的父亲结点的平衡因子,更新结束。

更新后parent的平衡因子等于1 或 -1,更新前更新中parent的平衡因子变化为0->1 或者 0->-1,说

明更新前parent子树两边⼀样高,新增的插入结点后,parent所在的子树⼀边高⼀边低,parent所

在的子树符合平衡要求,但是高度增加了1,会影响arent的父亲结点的平衡因子,所以要继续向上

更新。

更新后parent的平衡因子等于2 或 -2,更新前更新中parent的平衡因子变化为1->2 或者 -1->-2,说

明更新前parent子树⼀边高⼀边低,新增的插入结点在高的那边,parent所在的子树高的那边更高

了,破坏了平衡,parent所在的子树不符合平衡要求,需要旋转处理,旋转的⽬标有两个:1、把

parent子树旋转平衡。2、降低parent子树的高度,恢复到插入结点以前的高度。所以旋转后也不

需要继续往上更新,插入结束。

更新到10结点,平衡因子为2,10所在的子树已经不平衡,需要旋转处理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

更新到中间结点,3为根的子树高度不变,不会影响上⼀层,更新结束

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最坏更新到根停⽌

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv->first < kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}
		cur = new Node(kv);
		if (parent->_kv->first > kv.first)
		{
			parent->_left = cur;
			
		}
		else
		{
			parent->_right = cur;
			
		}
		//更新平衡因子
		while (parent)
		{
			if (cur == parent->_left)
				parent->_bf--;
			else
				parent->_bf++;
			if (parent->_bf == 0)
			{
				break;
			}
			else if (parent->_bf == -1 || parent->_bf == 1)
			{
				cur = parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == -2 || parent->_bf == 2)
			{
				//选转
				break;
			}

		}
	}

4、旋转

a、右单旋

本图1展⽰的是10为根的树,有a/b/c抽象为三棵高度为h的子树(h>=0),a/b/c均符合AVL树的要

求。10可能是整棵树的根,也可能是⼀个整棵树中局部的子树的根。这里a/b/c是高度为h的子树,

是⼀种概括抽象表示,他代表了所有右单旋的场景,实际右单旋形态有很多种,具体图2/图3/图4/

图5进行了详细描述。

在a子树中插入⼀个新结点,导致a子树的高度从h变成h+1,不断向上更新平衡因子,导致10的平

衡因子从-1变成-2,10为根的树左右高度差超过1,违反平衡规则。10为根的树左边太高了,需要

往右边旋转,控制两棵树的平衡。

旋转核心步骤,因为5 < b子树的值 < 10,将b变成10的左子树,10变成5的右子树,5变成这棵树新

的根,符合搜索树的规则,控制了平衡,同时这棵的高度恢复到了插入之前的h+2,符合旋转原

则。如果插入之前10整棵树的⼀个局部子树,旋转后不会再影响上⼀层,插入结束了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代码:

void RotateR(Node* parent)
{
	Node* Pparent = parent->_parent;
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	parent->_left = subLR;
	// 需要注意除了要修改孩子指针指向,还是修改父亲
	if (subLR)//防止对空指针解引用 
		subLR->_parent = parent;
	subL->_right = parent;
	parent->_parent = subL;
	if (Pparent == nullptr)//parent是根时
	{
		_root = subL;
		subL->_parent = nullptr;
	}
	else
	{
		if (parent == parentParent->_left)
		{
			parentParent->_left = subL;
		}
		else
		{
			parentParent->_right = subL;
		}
		subL->_parent = parentParent;
	}
	//更新平衡因子
	parent->_bf = subL->_bf = 0;
}

b、左单旋

本图6展示的是10为根的树,有a/b/c抽象为三棵高度为h的子树(h>=0),a/b/c均符合AVL树的要

求。10可能是整棵树的根,也可能是⼀个整棵树中局部的子树的根。这里a/b/c是高度为h的子树,

是⼀种概括抽象表示,他代表了所有右单旋的场景,实际右单旋形态有很多种,具体跟上⾯左旋类

似。

在a子树中插入⼀个新结点,导致a子树的高度从h变成h+1,不断向上更新平衡因子,导致10的平

衡因子从1变成2,10为根的树左右高度差超过1,违反平衡规则。10为根的树右边太高了,需要往

左边旋转,控制两棵树的平衡。

旋转核心步骤,因为10 < b子树的值 < 15,将b变成10的右子树,10变成15的左子树,15变成这棵

树新的根,符合搜索树的规则,控制了平衡,同时这棵的高度恢复到了插入之前的h+2,符合旋转

原则。如果插入之前10整棵树的⼀个局部子树,旋转后不会再影响上⼀层,插入结束了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代码:

void RotateL(Node* parent)
{
	Node* Pparent = parent->_parent;
	Node* subR = parent->_right;
	Node* subRL = subL->_left;
	parent->_right = subRL;
	if (subRL)
		subRL->_parent = parent;
	subR->_left = parent;
	parent->_parent = subR;
	if (Pparent == nullptr)//parent是根时
	{
		_root = subR;
		subR->_parent = nullptr;
	}
	else
	{
		if (parent == parentParent->_left)
		{
			parentParent->_left = subR;
		}
		else
		{
			parentParent->_right = subR;
		}
		subR->_parent = parentParent;
	}
	parent->_bf = subR->_bf = 0;
}

c、左右双旋

通过图7和图8可以看到,左边高时,如果插入位置不是在a子树,而是插入在b子树,b子树高度从h变

成h+1,引发旋转,右单旋无法解决问题,右单旋后,我们的树依旧不平衡。右单旋解决的纯粹的左边

高,但是插入在b子树中,10为跟的子树不再是单纯的左边高,对于10是左边高,但是对于5是右边

高,需要用两次旋转才能解决,以5为旋转点进行⼀个左单旋,以10为旋转点进行⼀个右单旋,这棵树

这棵树就平衡了

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图7和图8分别为左右双旋中h=0和h=1具体场景分析,下面我们将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。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

void RotateLR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	int bf = subLR->_bf;//根据subLR的平衡因子判断
	RotateL(parent->_left);
	RotateR(parent);
	if (bf == 0)
	{
		subL->_bf = 0;
		subLR->_bf = 0;
		parent->_bf = 0;
	}
	else if (bf == -1)
	{
		subL->_bf = 0;
		subLR->_bf = 0;
	}
	else if (bf == 1)
		parent->_bf = 1;
	{
		subL->_bf = -1;
		subLR->_bf = 0;
		parent->_bf = 0;
	}
	else
	{
		assert(false);
	}
}

d、右左双旋

跟左右双旋类似,下⾯我们将a/b/c子树抽象为⾼度h的AVL子树进⾏分析,另外我们需要把b子树的

细节进⼀步展开为12和左子树⾼度为h-1的e和f子树,因为我们要对b的⽗亲15为旋转点进⾏右单

旋,右单旋需要动b树中的右子树。b子树中新增结点的位置不同,平衡因子更新的细节也不同,通

过观察12的平衡因子不同,这⾥我们要分三个场景讨论。

场景1:h >= 1时,新增结点插⼊在e子树,e子树⾼度从h-1变为h并不断更新12->15->10平衡因

子,引发旋转,其中12的平衡因子为-1,旋转后10和12平衡因子为0,15平衡因子为1。

场景2:h >= 1时,新增结点插⼊在f子树,f子树⾼度从h-1变为h并不断更新12->15->10平衡因子,

引发旋转,其中12的平衡因子为1,旋转后15和12平衡因子为0,10平衡因子为-1。•

场景3:h == 0时,a/b/c都是空树,b自己就是⼀个新增结点,不断更新15->10平衡因子,引发旋

转,其中12的平衡因子为0,旋转后10和12和15平衡因子均为0。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

	RotateR(parent->_right);
	RotateL(parent);

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

三、整体代码

#pragma once
#include<iostream>
using namespace std;
template<class K, class V>
struct AVLTreeNode
{
	// 需要parent指针,后续更新平衡因⼦可以看到
	pair<K, V> _kv;
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;
	int _bf; // balance factor
	AVLTreeNode(const pair<K, V>& kv)
		:_kv(kv)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _bf(0)
	{}
};
template<class K, class V>
class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
	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)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv->first < kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}
		cur = new Node(kv);
		if (parent->_kv.first < kv.first)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		// 链接父亲
		cur->_parent = parent;
		if (parent->_kv->first > kv.first)
		{
			parent->_left = cur;
			
		}
		else
		{
			parent->_right = cur;
			
		}
		//更新平衡因子
		while (parent)
		{
			if (cur == parent->_left)
				parent->_bf--;
			else
				parent->_bf++;
			if (parent->_bf == 0)
			{
				break;
			}
			else if (parent->_bf == -1 || parent->_bf == 1)
			{
				cur = parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == -2 || parent->_bf == 2)
			{
				//选转
				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);
				}
				else
				{
					RotateRL(parent);
				}
				break;
			}

		}
	}
	void RotateR(Node* parent)
	{
		Node* Pparent = parent->_parent;
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		parent->_left = subLR;
		// 需要注意除了要修改孩⼦指针指向,还是修改⽗亲
		if (subLR)//防止对空指针解引用 
			subLR->_parent = parent;
		subL->_right = parent;
		parent->_parent = subL;
		if (Pparent == nullptr)//parent是根时
		{
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
			if (parent == parentParent->_left)
			{
				parentParent->_left = subL;
			}
			else
			{
				parentParent->_right = subL;
			}
			subL->_parent = parentParent;
		}
		//更新平衡因子
		parent->_bf = subL->_bf = 0;
	}
	void RotateL(Node* parent)
	{
		Node* Pparent = parent->_parent;
		Node* subR = parent->_right;
		Node* subRL = subL->_left;
		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;
		subR->_left = parent;
		parent->_parent = subR;
		if (Pparent == nullptr)//parent是根时
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
			if (parent == parentParent->_left)
			{
				parentParent->_left = subR;
			}
			else
			{
				parentParent->_right = subR;
			}
			subR->_parent = parentParent;
		}
		parent->_bf = subR->_bf = 0;
	}
	void RotateLR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		int bf = subLR->_bf;//根据subLR的平衡因子判断
		RotateL(parent->_left);
		RotateR(parent);
		if (bf == 0)
		{
			subL->_bf = 0;
			subLR->_bf = 0;
			parent->_bf = 0;
		}
		else if (bf == -1)
		{
			subL->_bf = 0;
			subLR->_bf = 0;
		}
		else if (bf == 1)
			parent->_bf = 1;
		{
			subL->_bf = -1;
			subLR->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}
	void RotateRL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		int bf = subRL->_bf;

		RotateR(parent->_right);
		RotateL(parent);

		if (bf == 0)
		{
			subR->_bf = 0;
			subRL->_bf = 0;
			parent->_bf = 0;
		}
		else if (bf == 1)
		{
			subR->_bf = 0;
			subRL->_bf = 0;
			parent->_bf = -1;
		}
		else if (bf == -1)
		{
			subR->_bf = 1;
			subRL->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}
private:
	Node * _root = nullptr;
};

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

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

相关文章

python开源代码自学问题解决(requests+openpyxl+pymysql)

目的 解决一下在一个开源代码中遇到的问题&#xff0c;作者已经学完了python的基础内容&#xff0c;因此找了一份开源的python代码进行学习&#xff0c;下面这份开源代码主要作用就是在拉勾网上获取与Python相关的职位信息&#xff0c;并将这些信息保存到本地的MySQL数据库中&…

【Linux】初始进程

目录 基本概念 PCB task_struct task_struct内容分类 组织进程 查看进程 查看正在运行的进程信息 获取pid和ppid 创建子进程 基本概念 一个已经加载到内存中的程序&#xff0c;叫做进程&#xff0c;正在运行的程序&#xff0c;叫做进程&#xff0c;进程是担当分配系统…

如果你不愿意冒一切风险,就不要成为创业者:如何建立一个年收入 1800 万美元的支付业务

作者&#xff1a;Austin Mac Nab&#xff0c;VizyPay 的 CEO 兼创始人 在创业初期&#xff0c;如果有人告诉我&#xff0c;我需要冒一切风险才能成功&#xff0c;我大概会吓得绕道而行。但事实是&#xff0c;如果你不愿意冒一切风险&#xff0c;就不要成为创业者。本着这个信念…

「JavaScript深入」彻底搞懂JS原型与原型链

JavaScript深入 — 原型与原型链 一、原因二、使用class实现继承普通的类实现继承 三、原型四、原型链小结原型原型链prototype和proto 引申 一、原因 JavaScript中除了基础类型外的数据类型&#xff0c;都是对象&#xff08;引用类型&#xff09;。但是由于其没有类&#xff…

央行放大招!潘行长发话了,现在能“贷款炒股“,这是真的吗?

9月&#xff0c;央行掌门人潘行长最新放话了&#xff0c;二套房贷款利率也得下调。这降准的利好一出&#xff0c;股市小涨了一波后又回到了原位&#xff0c;给全球金融市场带来了一股不同寻常的暖流。而非常有意思的是&#xff0c;在这次众多的金融政策大礼包当中&#xff0c;有…

CentOS8.5.2111(3)实验之DHCP服务器架设

一、实验目标 1&#xff0e;掌握DHCP服务器的主配置文件各项申明参数及操作及其含义 2. 具备DHCP 服务器、中继服务器的配置能力 3. 具备测试客户端正常获取服务器分配地址的能力 4. 具备DHCP服务器故障排除能力 二、实训原理/流程 &#xff08;一&#xff09;项目背景 …

媒界:助力民生保障 长城“消防炮”即将批量交付硬核守护万家灯火

一大波“消防炮”即将列装&#xff01; 日前&#xff0c;长城炮官方账号发布一条“‘消防炮’来了”的视频&#xff0c;引发广泛关注。视频显示一批长城炮车型已完成消防装备加装&#xff0c;华丽变身“消防炮”&#xff0c;整装待发&#xff0c;即将交付全国消防&#xff0c;…

创建型模式-简单工厂-工厂方法-抽象工厂

简单工厂模式 例题 uml 代码 package simpleFactory; import java.lang.management.OperatingSystemMXBean; import java.util.Scanner; //定义Person class Person{ public void say(){} } class Man extends Person{ public void say() { System.out.…

Transformer是不是BERT、GPT的妈?看完就知道了

Transformer变异衍生出来了两个超强悍的预训练模型 一、Transformer模型 Transformer是近年来深度学习领域中备受瞩目的模型之一&#xff0c;其核心思想是通过自注意力机制和位置编码来捕捉输入序列中的长距离依赖关系。 自注意力机制让模型在处理每个输入元素时能够关注到所有…

Mac电脑上最简单安装Python的方式

背景 最近换了一台新的 MacBook Air 电脑&#xff0c;所有的开发软件都没有了&#xff0c;需要重新配环境&#xff0c;而我现在最常用的开发程序就是Python。这篇文章记录一下我新Mac电脑安装Python的全过程&#xff0c;也给大家一些思路上的提醒。 以下是我新电脑的配置&…

Java入门2——基本数据类型详解

今天我们系统学习一下Java的八种基本数据类型&#xff0c;和C语言有些还是不太一样的&#xff0c;还是要打起精神&#xff0c;好好学习~ 一、Java的数据类型 首先我们画个图&#xff0c;了解一下Java的数据类型 以上就涵盖了Java的数据类型&#xff0c;那么下面&#xff0c;我…

C语言自定义类型:联合体

目录 前言一、联合体1.1 联合体类型的声明1.2 联合体的特点1.3 相同成员的结构体和联合体对比1.4 联合体大小的计算1.5 联合体的⼀个练习 总结 前言 前面我讲到C语言中的自定义结构——结构体&#xff0c;其实C语言中的自定义结构不只有结构体&#xff0c;还有枚举和联合体&am…

交通 | 上门配送or自提点配送?最后一公里配送中的需求引导问题

编者按&#xff1a; 为提高最后一公里配送的效率&#xff0c;本文将客户激励与不确定的路线决策相结合&#xff0c;建立了一个两阶段随即规划问题&#xff0c;并开发了一种精确式的分支定界算法进行求解。 摘要&#xff1a; 为了提高最后一公里配送的效率&#xff0c;零售商…

Vue 3 文件编译流程详解与 Babel 的使用

文章目录 一、背景二、结论三、vitejs/plugin-vue 插件调试前物料准备vuePlugin 入口buildStart 方法transform 方法 四、vue/compiler-sfc 核心包parse 方法compileScript、rewriteDefault 方法compileTemplate 方法 五、整体架构六、总结参考资料 一、背景 最近正在研究 rea…

企业防泄密妙招有哪些?请记住这8招!超实用,学起来!

在古代&#xff0c;有云&#xff1a;“密者&#xff0c;德之高也&#xff1b;事以密成&#xff0c;语以泄败。” 这些谚语不仅是对忠诚守密的高度赞扬&#xff0c;更是对保密工作重要性的深刻阐述。 在现代企业中&#xff0c;数据泄露已成为不容忽视的严峻挑战。 如何有效防止…

MFC单按钮启停实例

单击按钮启动、停止交替切欣换 1、在1Dlg.h文件中添加代码 public:CMy1Dlg(CWnd* pParent NULL); // standard constructorBOOL m_b;2、在1Dlg.cpp文件中添加代码 CMy1Dlg::CMy1Dlg(CWnd* pParent /*NULL*/): CDialog(CMy1Dlg::IDD, pParent) { m_hIcon AfxGetApp()->Lo…

高中还来得及选择信息学奥赛赛道吗?

随着信息学奥赛&#xff08;NOI&#xff09;在升学中的重要性日益凸显&#xff0c;越来越多的学生和家长将其视为进入顶尖高校的一个重要途径。然而&#xff0c;很多学生可能直到高中阶段才意识到信息学奥赛的重要性&#xff0c;或者才开始对编程产生兴趣。于是问题出现了&…

DarkLabel2.4版本导入MOT17数据集

目录 背景导入效果MOT17数据集说明DarkLabel导入视频导入gt文件 背景 做目标追踪&#xff0c;目前找了一圈开源工具&#xff0c;发现DarkLabel还是很好用的&#xff0c;提供自动目标跟踪&#xff0c;标注很方便。 由于目标追踪我用的是bytetrack&#xff0c;官网是用mot17数据…

学校周赛(2)

A.Minimize! 题目 思路 本题只需要遍历c的取值&#xff0c;实时更新答案即可 代码 #include<iostream> #include<algorithm> using namespace std;void todo(){int a,b;cin>>a>>b;int ansINT_MAX;for(int ca;c<b;c){ansmin(ans,(c-a)(b-c));}co…

二叉树的前序遍历,中序遍历,后序遍历以及层次遍历(递归方式+C语言代码)

#include<stdlib.h> #include<stdio.h> #include<assert.h> //定义一个二叉树结点结构体 typedef int ElemTpye; typedef struct TreeNode {ElemTpye data;struct TreeNode* left;struct TreeNode* right; }TreeNode; //创建结点 TreeNode* createTreenode(E…