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

【AVL树】—— 我与C++的不解之缘(二十三)

什么是AVL树?

  • AVL树发明者是G. M. Adelson-VelskyE. M. Landis两个前苏联科学家,他们在1962年论文《An algorithm for the organization of information》中发表了AVL树。
  • AVL树是最先发明的自平衡二叉搜索树,说白了就是能够自己控制平衡结构的一个二叉搜索树;AVL可以是一个空树,或者其左右树都是AVL树,且左右子树的高度差的绝对值不超过1。
  • AVL树,左右子树的高度差不超过一,而不是0?(如果一棵树的节点个数是2、4等的情况下,高度差最好情况就是1,到不到0。
  • 本篇在实现AVL树时,引入了一个新的概念(平衡因子);每个节点都存在平衡因子,平衡因子等于右子树的高度减去左子树的高度,这样平衡因子的取值就是(0、1、-1);(平衡因子也不是必须的,这里引入平衡因子这一概念,方便观察和控制整个AVL树的平衡。

​ 简单来说,AVL树就是一个特殊的搜索二叉树,特殊就特殊在它可以控制平衡,保持左右子树的高度差不超过1。

那又是如何实现的呢?

AVL树的实现

1. AVL树的结构

先来看一下AVL树的结构,首先就是AVL树的节点

template<class K,class V>
struct TreeNode {int _bf;pair<K, V> _kv;TreeNode<K, V>* _left;TreeNode<K, V>* _right;TreeNode<K, V>* _parent;TreeNode(const pair<K, V> kv):_kv(kv), _bf(0), _left(nullptr), _right(nullptr), _parent(nullptr){}
};

这里并没有直接存储数据K,和V,而是像map那样将其封装成一个pair<K,V>类型。

再来看一下AVL树都要实现哪些方法

template<class K,class V>
class AVLTree
{typedef TreeNode<K, V> Node;
public://插入bool insert(const pair<K, V> kv) {}//查找bool find(const K& kev) {}//中序遍历void order() {}
private://右单旋void RevoleR(Node* parent) {}//左单旋void RevoleL(Node* parent) {}//右左双选void RevoleRL(Node* parent) {}//左右双选void RevoleLR(Node* parent) {}//中序遍历void order(Node* root) {}Node* _root;
};

这里实现了几个私有的成员方法,因为这些方法不希望在类外被直接访问。(其中order()是为了实现中序遍历,因为在类外无法访问到该树的根节点。)

2. AVL树的插入

插入过程

对于插入数据的整个过程,其实就是在搜索二叉树的基础上,增加了更新平衡因子和在更新平衡因子的过程中需要旋转的情况就行旋转。

  • 按搜索二叉树的规则进行插入数据
  • 新增节点以后,就可能会影响到部分祖先节点的平衡因子,所以从新增节点 -> 根节点这整个路径上节点的平衡因子(在更新的过程中,可能会遇到继续更新,更新结束以及需要旋转的情况。)
  • 更新平衡因子过程中没有出现问题,插入就结束了。
  • 在平衡的过程中,出现了不平衡的情况,就要堆不平衡子树进行旋转,选择后调平衡的同时,也降低了子树的高度,就不会影响上一层的平衡因子,插入也就结束了。

更新平衡因子

首先,平衡因子=右子树高度-左子树高度

  • 插入节点会增加高度,所以,新增节点如果是在parent节点的右子树,则parent节点的平衡因子++;如果是在parent节点的左子树,那么parent节点的平衡因子–;
  • parent所在子树的高度是否变化就决定了是否要继续往上更新平衡因子。

更新平衡因子可能遇到的情况:

  • 更新之后parent节点平衡因子等于0:更新过程中parent的平衡因子变化-1->0或者1->0,这说明了插入节点之前parent子树一边高一边低,新增节点插入到了低的那一边,插入节点后以parent为根节点的子树的高度不变,就不会影响其父节点的平衡因子(就不会影响到上面节点的平衡)所以更新就结束了。
  • 更新之后parent节点平衡因子等于1或-1:更新过程中parent的平衡因子变化0->-1或者0->1,这就说明了,插入节点之前,parent的左右子树高度相同了,插入节点之后parent子树的高度发生了变化,所以就会影响其父节点的平衡因子,从而影响上面节点的平衡;所以需要继续更新平衡因子。
  • 更新之后parent节点平衡因子等于2或者-2:更新过程中parent的平衡因子变化1->2或者-1->-2,这说明,在插入节点之前,以parent为根节点的子树就已经一边高一边低了;然后新增节点还插入到了高的那一边,这样以parent为根节点的子树就已经不满足AVL树的结构了,此时就需要对该树就行旋转(旋转:一是将以parent为根节点的子树调整平衡,二是降低以parent为根节点的子树的高度,回复到插入以前的高度);旋转完成后,就不需要继续更新平衡因子了。

更新之后parent节点平衡因子为0

在这里插入图片描述

更新之后parent节点平衡因子为1或者-1

在这里插入图片描述

更新之后parent节点平衡因子为2或者-2
在这里插入图片描述

更新平衡因子的过程实现

bool insert(const pair<K, V> kv) 
{Node* newnode = Node(kv);if (_root == nullptr){_root = newnode;return true;}Node* parent = nullptr;Node* pcur = _root;while (pcur){if (kv.first > pcur->_kv.first){parent = pcur;pcur = pcur->_right;}else if (kv.first < pcur->_kv.first){parent = pcur;pcur = pcur->_left;}else{return false;}}pcur = newnode;newnode->_parent = parent;if (kv.first > parent->_kv.first){parent->_right = pcur;}else if (kv.first < parent->_kv.first){parent->_left = pcur;}else{return false;}//更新平衡因子while (parent){if (pcur == parent->_left){--parent->_bf;}else{++parent->_bf;}if (parent->_bf == 0){break;}else if (parent->_bf == 1 || parent->_bf == -1){pcur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2){//旋转}}	return true;
}

3.旋转

新插入节点以及更新平衡因子如上述,那么在更新平衡因子过程中,遇到平衡因子等于2(也就是以parent为根节点的子树不平衡)需要进行旋转,那如何旋转的呢?

旋转的规则:

  • 保持搜索树的原则。
  • 将要旋转的树从不满足到满足平衡,其次降低树的高度。

旋转一共分为四种(左单旋右单旋左右双旋右左双旋),其每一种旋转都对应一种情况;

左单旋

先来看一下这种情况:

在这里插入图片描述

如上图中以5为根节点的子树,其中abc都是高度为h的子树(h可以等于0);现在要在a子树中插入一个节点,在更新平衡因子的过程中,5所在节点的平衡因子1 -> 2,此时该子树就不平衡了,需要进行旋转;

通过观察上图,我们可以发现,5节点的右子树太高了,所以我们需要向左旋转来平衡高度;

如何旋转呢?

旋转步骤

  • b子树变成5节点的右子树;
  • 5节点为根节点的子树变成10节点的左子树;
  • 10节点就变成了这个子树新的根节点。

在这里插入图片描述

其中5<b子树<10,所以将b子树变成5的右子树,以5为根节点的子树变成10的左子树,仍然满足搜索二叉树的规则;

然后10节点变成了这部分子树新的根节点。(并不一定是整个子树新的根节点)。

代码实现:

//左单旋
void RevoleL(Node* parent) 
{//旋转节点的右孩子节点Node* subr = parent->_right;//旋转节点的右孩子节点的左孩子节点Node* subrl = parent->_right->_left;//subrl变成parent的右子树parent->_right = subrl;//subrl可能为空if (subrl)subrl->_parent = parent;//parent->变成subr的左子树subr->_left = parent;//记录parent的父节点Node* pnode = parent->_parent;parent->_parent = subr;//如果parent是整个avl树的根节点if (pnode == nullptr){_root = subr;subr->_parent = nullptr;}else{//parent父节点不为空subr->_parent = pnode;if (pnode->_left == parent){pnode->_left = subr;}else{pnode->_right = subr;}}//调整完之后将parent节点与subr节点的平衡因子修改成0parent->_bf = 0;subr->_bf = 0;
}
右单旋

了解了左单旋,右单旋就十分简单了:

在这里插入图片描述

和左单旋的情况相似,有单旋就是10节点的左子树高,需要进行右单旋;

旋转步骤

  • b子树变成10节点的左子树;
  • 10节点为根节点的子树变成5节点的右子树;
  • 5节点就变成这部分子树的根节点。

在这里插入图片描述

其中5<b子树<10,所以将b子树变成10的左子树,以10为根节点的子树变成5的右子树;仍然保持搜索二叉树的结构。

5节点就变成了这部分子树的根节点。

代码实现

//右单旋
void RevoleR(Node* parent)
{//旋转节点的左孩子节点Node* subl = parent->_left;//旋转节点的左孩子节点的右孩子节点Node* sublr = parent->_left->_right;//sublr变成parent的左孩子节点parent->_left = sublr;//sublr可能为nullptrif (sublr)sublr->_parent = parent;//parent变成subl的右孩子节点subl->_right = parent;//记录parent的父节点Node* pnode = parent->_parent;if (pnode == nullptr){_root = subl;subl->_parent = nullptr;}else{subl->_parent = pnode;if (pnode->_left == parent){pnode->_left = subl;}else{pnode->_right = subl;}}//修改parent 和 subl 的平衡因子parent->_bf = 0;subl->_bf = 0;
}
左右双旋

左单旋、右单旋都是纯粹的一边高(就是在parent左/右孩子的左/右孩子所在子树中插入数据);按上述说,就是在a子树中插入数据,但是如果是在b子树中插入数据呢?

在这里插入图片描述

如上图,我们很显然不能单纯的使用右单旋或者左单旋来解决问题了;

旋转步骤

左右双旋其实就是,先对parent的左孩子节点进行一次左单选,再对parent节点进行一次右单旋;

来看分析:

这里h是能够等于0的,我们分开来讨论:
h=0

在这里插入图片描述

我们先对subl节点进行一次左单旋,再对parent节点进行一次右单旋;

在这里插入图片描述

h!=0

对于h!=0的情况,b子树中就至少有一个节点,那我们要分为两种情况讨论;

我们将一个avl树抽象成下面这种情况:

在这里插入图片描述

这样我们可以看出来,可能是在e子树中插入数据,也可能是在f子树中插入数据;那这两种情况就也要分开讨论:

e子树中插入

在这里插入图片描述

此时,我们还是先对subl节点左单旋,变成纯粹的一边高,再对parent节点进行右单旋;

在这里插入图片描述

f子树插入节点

在这里插入图片描述

还是先对subl左单旋,再对parent进行右单旋;

在这里插入图片描述

通过观察,我们可以发现,这三种情况都是进行了一次左单旋和一次右单旋,不同的是其结果中sublparent的平衡因子不同。

这样我们在实现时,就直接复用左单旋右单旋就好了,然后根据其平衡因子的情况来判断最后sublparent节点的平衡因子即可。

更新平衡因子

  • sublr节点平衡因子等于0sublrsublparent平衡因子都为0
  • sublr节点平衡因子等于-1sublrsubl平衡因子等于0parent平衡因子等于1
  • sublr节点平衡因子等于1sublrparent平衡因子等于0subl平衡因子等于-1

代码实现

代码实现过程中有一个细节就是:

在进行左右单旋时,会将平衡因子修改成0,我们就需要先记录一下sublr原本的平衡因子,来保证我们单旋结束后的平衡因子的修改。

	//左右双选void RevoleLR(Node* parent) {Node* subl = parent->_left;Node* sublr = parent->_left->_right;int bf = sublr->_bf;//对subl进行左单旋RevoleL(subl);//对parent进行右单旋RevoleR(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;}}
右左双旋

右左双旋左右双旋逻辑非常像,这里就不演示了,直接看代码实现:

	//右左双选void RevoleRL(Node* parent) {Node* subr = parent->_right;Node* subrl = parent->_right->_left;int bf = subrl->_bf;RevoleR(subr);RevoleL(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;}}

在旋转实现完成之后我们就可以完善我们insert了:

//插入
bool insert(const pair<K, V> kv) 
{Node* newnode = Node(kv);if (_root == nullptr){_root = newnode;return true;}Node* parent = nullptr;Node* pcur = _root;while (pcur){if (kv.first > pcur->_kv.first){parent = pcur;pcur = pcur->_right;}else if (kv.first < pcur->_kv.first){parent = pcur;pcur = pcur->_left;}else{return false;}}pcur = newnode;newnode->_parent = parent;if (kv.first > parent->_kv.first){parent->_right = pcur;}else if (kv.first < parent->_kv.first){parent->_left = pcur;}else{return false;}//更新平衡因子while (parent){if (pcur == parent->_left){--parent->_bf;}else{++parent->_bf;}if (parent->_bf == 0){break;}else if (parent->_bf == 1 || parent->_bf == -1){pcur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2){//旋转if (parent->_bf == 2 && parent->_left->_bf == 1){//左单旋RevoleL(parent);}else if (parent->_bf == 2 && parent->_left->_bf == -1){//右左双旋RevoleRL(parent);}else if (parent->_bf == -2 && parent->_right->_bf == -1){//右单旋RevoleR(parent);}else if (parent->_bf == -2 && parent->_left->_bf == 1){//左右双旋RevoleLR(parent);}}}return true;
}

旋转了解完以后,就可以完善之前的插入功能了:

//插入
bool insert(const pair<K, V> kv) 
{Node* newnode =  new Node(kv);if (_root == nullptr){_root = newnode;return true;}Node* parent = nullptr;Node* pcur = _root;while (pcur){if (kv.first > pcur->_kv.first){parent = pcur;pcur = pcur->_right;}else if (kv.first < pcur->_kv.first){parent = pcur;pcur = pcur->_left;}else{return false;}}pcur = newnode;newnode->_parent = parent;if (kv.first > parent->_kv.first){parent->_right = pcur;}else if (kv.first < parent->_kv.first){parent->_left = pcur;}else{return false;}//更新平衡因子while (parent){if (pcur == parent->_left){--parent->_bf;}else{++parent->_bf;}if (parent->_bf == 0){break;}else if (parent->_bf == 1 || parent->_bf == -1){pcur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2){//旋转if (parent->_bf == 2 && parent->_left->_bf == 1){//左单旋RevoleL(parent);}else if (parent->_bf == 2 && parent->_left->_bf == -1){//右左双旋RevoleRL(parent);}else if (parent->_bf == -2 && parent->_right->_bf == -1){//右单旋RevoleR(parent);}else if (parent->_bf == -2 && parent->_left->_bf == 1){//左右双旋RevoleLR(parent);}}}return true;
}

4. AVL树的查找

AVL树的查找先对就简单多了,和搜索二叉树查找一样。

	//查找bool find(const K& kv) {Node* ptail = _root;while (ptail){if (kv.first > ptail->_kv->first){ptail = ptail->_right;}else if (kv.first < ptail->_kv->first){ptail = ptail->_left;}else{return true;}}return false;}

对于AVL树的删除,有点过于复杂,感兴趣的可以深入探究一下;后面研究过了再来探讨这个问题。

}else if (parent->_bf == -2 && parent->_right->_bf == -1){//右单旋RevoleR(parent);}else if (parent->_bf == -2 && parent->_left->_bf == 1){//左右双旋RevoleLR(parent);}}
}
return true;

}


## 4. `AVL`树的查找`AVL`树的查找先对就简单多了,和搜索二叉树查找一样。```cpp//查找bool find(const K& kv) {Node* ptail = _root;while (ptail){if (kv.first > ptail->_kv->first){ptail = ptail->_right;}else if (kv.first < ptail->_kv->first){ptail = ptail->_left;}else{return true;}}return false;}

对于AVL树的删除,有点过于复杂,感兴趣的可以深入探究一下;后面研究过了再来探讨这个问题。

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2oul0hvapjsws

相关文章:

【AVL树】—— 我与C++的不解之缘(二十三)

什么是AVL树&#xff1f; AVL树发明者是G. M. Adelson-Velsky和E. M. Landis两个前苏联科学家&#xff0c;他们在1962年论文《An algorithm for the organization of information》中发表了AVL树。AVL树是最先发明的自平衡二叉搜索树&#xff0c;说白了就是能够自己控制平衡结构…...

用大白话解释日志处理Log4j 是什么 有什么用 怎么用

Log4j是什么&#xff1f; Log4j就像程序的“黑匣子”&#xff0c;专门用来记录软件运行时的各种信息&#xff0c;比如哪里报错、性能如何、用户操作轨迹等。它是Java领域最常用的日志框架之一&#xff0c;可以灵活控制日志内容、输出位置&#xff08;控制台、文件、数据库等&a…...

无人机遥控器的亮度 和 两个工作频率

工作频率 2.4000-2.4835 GHz &#xff0c; 5.725-5.850 GHz 1.这是一个无人机的遥控器的两个工作频率&#xff0c;为什么会有两个工作频率&#xff1f; 无人机的遥控器采用双频段设计&#xff08;2.4GHz 和 5.8GHz&#xff09;&#xff0c;主要是为了解决以下问题并优化性…...

【Linux】命令行参数 | 环境变量(四)

目录 前言&#xff1a; 一、命令行参数&#xff1a; 1.main函数参数 2.为什么有它&#xff1f; 二、环境变量&#xff1a; 1.main函数第三个参数 2.查看shell本身环境变量 3.PATH环境变量 4.修改PATH环境变量配置文件 5.HOME环境变量 6.SHELL环境变量 7.PWD环境变…...

算法002——复写零

力扣——复写零点击即可跳转 这道题还是运用 双指针&#xff0c;我们从左往右开始&#xff0c;让 cur 0&#xff0c;dest 0,当我们循环时&#xff0c;会覆盖后面的值&#xff0c;所以从左到右无法实现&#xff0c;我们运用 从右到左的方式。 以示例一数组为例&#xff0c;从…...

例子 DQN + CartPole: 深入思考一下,强化学习确实是一场智能冒险之旅!

强化学习的概念 在技术人员眼里&#xff0c;深度学习、强化学习&#xff0c;或者是大模型&#xff0c;都只是一些算法。无论是简单&#xff0c;还是复杂&#xff0c;我们都是平静的看待。当商业元素日益渗透进技术领域&#xff0c;人人言必称大模型的时候。技术人该反思一下&a…...

java 实现xxl-job定时任务自动注册到调度中心

xxl-job 自动注册(执行器和任务) 前言 xxl-job是一个功能强大、简单易用、高可用且可扩展性强的分布式定时任务框架/分布式任务调度平台。它适用于各种需要定时任务调度的场景,并可根据业务需求进行灵活配置和扩展。 xxl-job简介 xxl-job是一个开源的分布式定时任务框架,…...

esp32串口通信

1、线路图 2、打开电脑的串口终端 3、eps32通过串口往电脑的串口终端输出信息&#xff1a; from machine import UART, Pin import time# 初始化UART0&#xff0c;波特率设置为115200 uart UART(0, baudrate115200, tx1, rx3)# 主循环 while True:# 要发送的消息#某些串口终…...

蓝桥杯备赛-前缀和-可获得的最小取值

问题描述 妮妮学姐手头有一个长度为 nn 的数组 aa&#xff0c;她想进行 kk 次操作来取出数组中的元素。每次操作必须选择以下两种操作之一&#xff1a; 取出数组中的最大元素。取出数组中的最小元素和次小元素。 妮妮学姐希望在进行完 kk 次操作后&#xff0c;取出的数的和最…...

UniApp 中封装 HTTP 请求与 Token 管理(附Demo)

目录 1. 基本知识2. Demo3. 拓展 1. 基本知识 从实战代码中学习&#xff0c;上述实战代码来源&#xff1a;芋道源码/yudao-mall-uniapp 该代码中&#xff0c;通过自定义 request 函数对 HTTP 请求进行了统一管理&#xff0c;并且结合了 Token 认证机制 请求封装原理&#xff…...

边缘计算+多模态感知:户外监控核心技术解析与工程部署实践!户外摄像头监控哪种好?户外摄像头监控十大品牌!格行视精灵VS海康威视VS大华横评!

一、核心参数解析与选型逻辑 1.环境适应性设计 极端天气防护&#xff1a;优先选择IP66/67防护等级的设备&#xff0c;例如格行视精灵通过IP67防水防尘设计可应对暴雨、沙尘暴等复杂环境&#xff0c;其密封轴承结构可有效防止水汽侵蚀内部电路。 温度耐受范围&#xff1a;北方…...

Spring项目-抽奖系统(实操项目)(ONE)

^__^ (oo)\______ (__)\ )\/\ ||----w | || || 一&#xff1a;前言&#xff1a; 随着互联网技术的快速发展&#xff0c;线上营销活动已成为企业吸引用户、…...

STM32-智能小车项目

项目框图 ST-link接线 实物图&#xff1a; 正面&#xff1a; 反面&#xff1a; 相关内容 使用L9110S电机模块 电机驱动模块L9110S详解 | 良许嵌入式 测速模块 语音模块SU-03T 网站&#xff1a;智能公元/AI产品零代码平台 一、让小车动起来 新建文件夹智能小车项目 在里面…...

Python:字符串常见操作

find(子字符串&#xff0c;开始位置下标&#xff0c;结束位置下标) 注意&#xff1a;开始位置和结束位置下标可以省略&#xff0c;表示在整个字符串中查找 stasdfghjkl print(st.find(a))#输出结果为0&#xff0c;表明a在第一个位置默认从零开始&#xff0c;找不到则返回-1 …...

Redis 哈希(Hash)

Redis 哈希(Hash) 概述 Redis 哈希&#xff08;Hash&#xff09;是一种特殊的键值对类型&#xff0c;它允许存储结构化的数据&#xff0c;例如一个对象或记录。每个哈希值可以包含多个字段&#xff0c;每个字段又可以存储一个字符串值。这使得Redis哈希非常适合用于存储对象的…...

Windows对比MacOS

Windows对比MacOS 文章目录 Windows对比MacOS1-环境变量1-Windows添加环境变量示例步骤 1&#xff1a;打开环境变量设置窗口步骤 2&#xff1a;添加系统环境变量 2-Mac 系统添加环境变量示例步骤 1&#xff1a;打开终端步骤 2&#xff1a;编辑环境变量配置文件步骤 3&#xff1…...

react 路由跳转的几种方式

在 React 中&#xff0c;路由跳转通常通过 react-router-dom&#xff08;或类似的路由库&#xff09;来实现。以下是几种常见的路由跳转方式&#xff1a; 1. 使用 <Link> 组件 <Link> 是最简单的路由跳转方式&#xff0c;它会生成一个 <a> 标签&#xff0c…...

2.你有什么绝活儿?—Java能做什么?

1、Java的绝活儿&#xff1a;要问Java有什么绝活&#xff0c;我觉得它应该算是一位魔法师&#xff0c;会的绝活儿有很多&#xff0c;要说最能拿得出手的当属以下三个。 1.1 平台无关性&#xff1a;Java可以在任何地方施展魔法&#xff0c;无论是Windows、Linux还是Mac&#xf…...

2025年2月文章一览

2025年2月编程人总共更新了17篇文章&#xff1a; 1.2025年1月文章一览 2.《Operating System Concepts》阅读笔记&#xff1a;p2-p8 3.《Operating System Concepts》阅读笔记&#xff1a;p9-p12 4.《Operating System Concepts》阅读笔记&#xff1a;p13-p16 5.《Operati…...

C++ | 面向对象 | 类

&#x1f47b;类 &#x1f47e;语法格式 class className{Access specifiers: // 访问权限DataType variable; // 变量returnType functions() { } // 方法 };&#x1f47e;访问权限 class className {public:// 公有成员protected:// 受保护成员private:// 私有成员 }…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...