深入学习二叉树(BinaryTree)(纯小白进)
目录:
- 一、 前言
 - 二、 正文
 - 2.1、 树的概念
 - 2.1.1、 树的结构
 - 2.1.2、 树的小知识
 
- 2.2、 认识二叉树
 - 2.2.1、 二叉树的概念
 - 2.2.2、 特殊的二叉树
 
- 2.3、 实现二叉树
 - 2.3.1、 结构
 - 2.3.2、 节点数
 - 2.3.3、 树深度
 - 2.3.4、 前、中、后序遍历 + 销毁
 - 2.3.4.1、 前序遍历
 - 2.3.4.2、 中序遍历
 - 2.3.4.3、 后序遍历
 - 2.3.4.4、 二叉树的销毁
 
- 2.4、 玩转二叉树
 - 2.4.1、 构建树
 - 2.4.2、 层序遍历
 - 2.4.3、 判断是否为完全二叉树
 
- 三、总结
 
一、 前言
二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。简言之,二叉树是数据结构中非常重要的东西,在很多OJ试题和笔试题中,都会出现它的影子;后续我们也会学到各种各样的树,比如二叉搜索树、AVL树、红黑树、B树等都是基于二叉树的高阶树。总之,现在把普通二叉树学好了,对以后的学习是十分有帮助的。
Tips:
二叉树的学习与之前略有不同,我们不讨论普通二叉树的增删查改,因为对于普通二叉树来说,这些操作意义不大
二、 正文
2.1、 树的概念
2.1.1、 树的结构
- 树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
 - 有一个特殊的结点,称为根结点,根节点没有前驱结点 除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1<= i<= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继。
 - 树可以理解为是递归定义的.
 

**这里需要注意的是:**树形结构中,子树之间不能有交集,否则就不是树形结构。

2.1.2、 树的小知识

- 节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6。
 - 叶节点或终端节点:度为0的节点称为叶节点; 如上图:B、C、H、I…等节点为叶节点。
 - 非终端节点或分支节点:度不为0的节点; 如上图:D、E、F、G…等节点为分支节点。
 - 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点。
 - 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点。
 - 兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点。
 - 树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6。
 - 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推。
 - 树的高度或深度:树中节点的最大层次; 如上图:树的高度为4。
 - 堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:H、I互为兄弟节点。
 - 节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先。
 - 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙。
 - 森林:由m(m>0)棵互不相交的树的集合称为森林。
 
上面我们先认识一下树,以便我们接下来继续学习二叉树可以更好地理解二叉树。
2.2、 认识二叉树
2.2.1、 二叉树的概念
一棵二叉树是结点的一个有限集合,该集合:
- 或者为空
 - 由一个根节点加上两棵别称为左子树和右子树的二叉树组成d
 

从上图看出:
- 二叉树不存在度大于2的结点
 - 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树
 
二叉树会有以下几种情况复合而成的:

2.2.2、 特殊的二叉树

- 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是 ,则它就是满二叉树。
 - 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 满二叉树是一种特殊的完全二叉树。简单来说,就是最后一层从左到右是不间断的节点。
 
以下两张神图,来源于网络:

如上图所示,这是一棵现实中的二叉树,我们看着很形象,也很容易理解 “二叉” 这个概念,不过计算机可不这样认为,在它眼中二叉树要么长这样 [1,2,3,4,5],要么长这样 1->2->3->4->5
 没错,二叉树在计算机中可以有两种表示形式
- 顺序结构 
- 即以
数组的形式存储节点信息,这种结构一般用于存储完全二叉树 - 比如接下来要学的
堆,因为数组正好符合完全二叉树连续存储的要求 
 - 即以
 - 链式结构 
- 即以
链表的形式存储节点信息,这种结构可以用于所有二叉树,本文代码结构也是以链式为主 二叉树普遍都是不规则的,数组难以满足节点分散这个要求
 - 即以
 
知道结构后还需加以规则限制,
二叉树的规则有
- 空树也可以看作
 二叉树- 任何一棵
 二叉树,都可以分为根、左子树、右子树二叉树中不存在度大于2的节点(度即当前节点的子树数量)二叉树的子树有左右之分,顺序不可颠倒,即左边一定是左树
了解以上关于二叉树的相关性质,接下来,咱们来看一下关于二叉树的具体实现
2.3、 实现二叉树
这部分主要是实现一些简单功能,涉及大量递归知识。
2.3.1、 结构
前面说过,二叉树主要有两种表现形式,通常我们采用链式结构(链式二叉树)来实现。
 任何一棵二叉树都有根、左、右三部分,细化到一个节点也是如此,因此链式二叉树在结构上分为以下三部分
- 数据域,负责存放当前节点的元素信息
 - 左子树(左孩子),指向左树的指针
 - 右子树(右孩子),指向右树的指针
 
二叉树的实现和创建如下:
typedef char BTDataType;	//二叉树的数据类型typedef struct BinaryTreeNode
{BTDataType data;	//存储节点的元素信息,每个节点都有struct BinaryTreeNode* left;	//左子树(左孩子)struct BinaryTreeNode* right;	//右子树(右孩子)
}BTNode;
//申请节点
BTNode* BuyNode(BTDataType x) {BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL) {perror("malloc fail");return NULL;}node->data = x;node->left = node->right = NULL;return node;
}BTNode* CreateTree() {BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);BTNode* node7 = BuyNode(7);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;//node3->right = node7;return node1;}
 
注意: 因为
链式二叉树每次都需要单独申请节点,因此没有初始化函数,但每个节点都有初始化状态: *数据域置0,左右子树都指向空* 。二叉树的销毁需要借助递归+后序遍历的方式销毁,后面会提及
2.3.2、 节点数
为了方便后续功能的讲解,先在假设存在一棵二叉树,形状如下所示,代码实现时由自己手动进行申请、赋值、链接
 
关于二叉树的节点数
- 对于
二叉树来说,不为空的都可以称为一个节点,如上图所示,共计5个节点,其中节点 'A ’ 为根节点(root) - 统计
二叉树节点需要巧妙利用递归,大问题化为小问题 
如何递归呢?
 众所周知,递归是个技巧,代码极其简洁,但不太好懂,也不太好调试,并且存在很多问题(栈溢出、运行效率低等),但这丝毫不妨碍我们在这里使用它,理由如下:
- 首先我们需要统计的是整棵
二叉树的节点数,已知任何一棵二叉树都可以看成 n 棵树组成的树,而每二叉棵树都有根、左、右三部分组成 - 其中如果根不为空,那么这个节点就是有效节点,可以参与统计,为空就不参与
 - 现在我们只考虑一个节点是否合法,如果合法,那么返回1,兵分两路走向它的左右子树,继续判断
 - 观察发现
二叉树肯定存在边界,比如上图,最底层的空就是边界,当我们往下递归,碰到空时,直接返回,不再往下判断 - 整个过程符合
递归要求:有终止条件+接近手段,我们可以从根节点开始往下递出,最后返回每次判断所得到的节点数就行了(要么是0,要么是1),这就是递归 - 这个思想比较重要,后面很多函数都是走的这个思想
 
长话短说,借助递归+二叉树的特性,将整个二叉树走一遍,如果发现当前节点为空,就不往下走,否则会一直往下走,总体路径为 根 -> 左 -> 右,最后会回归每次判断所得的节点数,整个过程如图所示,这是一个比较长的 动图,耐心看完
 
 代码实现如下所示
// 二叉树节点个数
int TreeSize(BTNode* root)
{//一级指针,不能断言,不然就无法递归//就是说,这里root为空是递归终止的条件,如果断言,就永远不可能达到终止,一直递归下去if (!root)return 0;return 1 + TreeSize(root->left) + TreeSize(root->right);	//根 + 左 + 右//或者//return root==NULL?0: TreeSize(root->left) + TreeSize(root->right) + 1;
}
 
注意: 除了单纯统计二叉树节点数外,还有一个变种:
统计第k层节点数,需要借助k,每下潜一层,k-1,直到 k 为1时,才计数返回。
代码实现如下所示
//求第k层的节点个数
//根的第k层=左子树的第k-1层+右子树的第k-1层
int TreeKLevel(BTNode* root, int k) {//没有说k是负层的assert(k > 0);if (root == NULL)return 0;if (k == 1)return 1;int leftK = TreeKLevel(root->left, k - 1);int rightK = TreeKLevel(root->right, k - 1);//不建议直接写成下面,是因为每次计算的话都要去在计算一遍结果,效率很低//return TreeKLevel(root->left, k - 1)+ TreeKLevel(root->right, k - 1);return leftK + rightK;
}
 
2.3.3、 树深度
二叉树的深度,指根节点的左右子树深度中的较大值,假如根的左子树深度为3,右子树的深度为1,那么整棵树的深度为3,同样的,需要借助递归,步骤如下
- 设两个变量:
leftHeight和rightHeight,分别用来存储左右子树的深度 - 左右子树的深度即左右子树的节点数,统计方式与上面函数类型
 - 得到这两个深度后,判断谁是较大的一方,返回它
 - 这也是个典型的
递归,终止条件为节点为空,接近手段为向下移动
这个的代码量也很少,无非就是比上面多了两句 
//二叉树的深度
int TreeHeight(BTNode* root) {if (root == NULL)return 0;int leftHeight = TreeHeight(root->left);int rightHeight = TreeHeight(root->right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
 
2.3.4、 前、中、后序遍历 + 销毁
学校最喜欢考的东西,其实很简单,我们直接三剑齐发,再附带一个销毁
 遍历思想:
- 前、中、后序思想一致,无非就是出发点和结束点不一样罢了
 - 前序:根出发,最右子树结束
 - 中序:最左子树出发,最右子树结束
 - 后序:最左子树出发,根结束
 - 三种方式遍历代码量可以说是完全一致,只不过顺序不同罢了
 
关于这三种遍历方式,我想直接通过三张动图解决,单独将没啥意义,复读而已,还不如动图来的直观
2.3.4.1、 前序遍历

 代码如下
// 二叉树前序遍历 
void PreOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;} printf("%d ", root->data);PreOrder(root->left);PreOrder(root->right);}
 
2.3.4.2、 中序遍历
代码如下
// 二叉树中序遍历
void InOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);}
 
2.3.4.3、 后序遍历

 代码如下
// 二叉树后序遍历
void PostOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}
 
2.3.4.4、 二叉树的销毁
二叉树的销毁其实和后续遍历差不多,不过是把打印换成了 free 当前节点,其实也很好理解,想要销毁整棵二叉树就得从最后一层开始往上销毁,如果先销毁的是上面的节点,那么下面的节点就丢失了,如此看来,只有后序符合这个要求,通过后序遍历能完美销毁整棵二叉树,代码如下
// 二叉树销毁
//销毁 ---后序销毁
void BTDestroy(BTNode* root) {if (root == NULL)return;BTDestroy(root->left);BTDestroy(root->right);free(root->left);free(root->right);free(root);
} 
 
2.4、 玩转二叉树
二叉树的热身环节已经结束了,现在准备进入更高难度的函数,带你从多种角度玩转二叉树
2.4.1、 构建树
首先来看看这个热门题:根据一个已知数组(存放的是某二叉树前序遍历的结果,# 表示空),构建出原二叉树。 题目的意思很简单,就是提供某二叉树的前序遍历结果,包括空也提供了,让我们根据这个结果,还原出原来的二叉树,前序遍历我们已经解决了,反过来还不简单?步骤如下
- 根据题目可知,数组中的 
#表示空,反过来说,如果遇到的不是#,那就说明这是一个节点 - 如果是 
#,直接return NULL;否则就申请一个节点,将此节点看作根节点 - 每次递归函数要么产生新节点,要么直接返回 
NULL,利用前序遍历思想,在得到根节点后,递归链接其左右孩子,至于孩子是节点还是NULL,得看递归结果 - 最后再返回当前节点信息,除了根节点可以返回出函数外,其他的节点信息都是返回给上一层节点,即成为他们的左右孩子,返回时,整棵树才会被链接起来
 
长话短说,这就是一个递归遍历数组+申请节点链接的程序,每次递归,都得保证数组递归遍历能往后走,前序思想为 根、左、右,大问题转小问题:先保证这个节点存在,再链接其左右孩子。代码实现时需要多加小心,比如传递数组下标时,要传地址,不然数组都走不下去,还有递归终止条件为当前数组值是否为 # ,接近手段就是数组的遍历,具体看**动图**实现:
 
 代码如下
// 通过前序遍历的数组"A B D # # E # H # # C F # # G # #"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{assert(a);//如果一开始就为 # 就没必要创建了if (a[*pi] == '#'){(*pi)++;	//向后移动,找到下一个值return NULL;}BTNode* node = (BTNode*)malloc(sizeof(BTNode));assert(node);node->data = a[(*pi)++];	//赋值,并向后移动node->left = BinaryTreeCreate(a, n, pi);	//左右链接node->right = BinaryTreeCreate(a, n, pi);return node;	//最开始的节点就是根节点
}
 
注意: 参数【数组下标】,需要
传地址,不然数组遍历就无法进行下去
2.4.2、 层序遍历
层序遍历,又被称为 广度优先遍历,之前是前、中、后序都属于深度优先遍历,所谓广度优先,就是一层一层的遍历,比如最开始的演示二叉树,层序遍历结果为:A B C D E
 层序遍历不必依靠递归,但是需要借助队列,因为队列的性质很符合广度这个要求(如果大家对队列存在疑惑的,大家可以移步这边)
- 队列的性质:
先进先出,后进后出(FIFO) 
具体实现步骤:
- 核心思想:先将根节点入队,然后出队,带根节点的下一层入队(如果存在的话)
 - 当根节点入队,出队打印后,把第二层的节点入队
 - 如此重复,直到每层所有节点遍历完毕
 - 循环终止条件是
队列是否为空,当队列为空时,说明整棵二叉树都入过队了 
层序遍历具体 **动图**如下 :
 
 代码如下
// 层序遍历
void  LeverOrder(BTNode* root) {Queue q;QueueInit(&q);if (root)QueuePush(&q, root);//root不为空,就把它push到队列中while (!QueueEmpty(&q)) {//用树节点保存出队列的节点BTNode* front = QueueFront(&q);QueuePop(&q);printf("%d ", front->data);//如果左右子树不为空,就进队列,进指针,不是数值if (front->left)QueuePush(&q, front->left);if (front->right)QueuePush(&q, front->right);}QueueDestroy(&q);
}
 
注意: 这里借助了
队列,需要引出相关头文件,入队列的元素是指向二叉树节点的指针,即二叉树节点在队列相关头文件中,需要特别注意一下,把队列`元素类型修改为对应类型
2.4.3、 判断是否为完全二叉树
这是力扣上的中等题,牛客上的困难题,也是本文的压轴戏
 完全二叉树,指连续的二叉树,判断是否为完全二叉树的关键就是 判断当前树是否连续(每一层都要连续),涉及到层序遍历,一样需要借助队列,不过循环终止条件和入队条件不同,也不需要打印了,只是多了一个判断,步骤如下:
- 提前统计出
二叉树的节点树,存储在变量countNode中,循环countNode次 - 核心思想仍然为 出上一层,带下一层
 - 原
层序遍历中的打印当前出队得到的节点,会被替换成判断当前节点是否为空 - 原
层序遍历中,为空的节点是入不了队的,但这里不管当前节点的左右子树是否为空,都入队,假如不是完全二叉树,那么肯定就存在循环未终止的情况下,出队取到空节点 - 用节点数作为循环终止条件,如果是
完全二叉树,是肯定取不到空节点的,因为它根本没机会入队 - 这样一来,问题就很好解决了,无非就是 入队、出队、判断、入队 如此重复
代码如下 
//判断是否为完全二叉树
bool  BTComplete(BTNode* root) {Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)) {BTNode* front = QueueFront(&q);QueuePop(&q);//为空就跳出来if (front==NULL) {break;}else {//不为空就把他的左右子节点push到队列中进去QueuePush(&q, root->left);QueuePush(&q, root->right);}}//再把队列全部出空while (!QueueEmpty(&q)) {BTNode* front = QueueFront(&q);QueuePop(&q);//如果有非空,说明队列中还存在非空节点,不是完全连续if (front) {QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}
 
三、总结
以上就是二叉树的全部内容了,回顾全文,我们从介绍树的相关性质,到了解了二叉树的相关概念,学习了二叉树的基础功能和实现,相信你在看完本文后,一定能学到很多干货,轻松理解二叉树!,下一站:堆
相关文章:
深入学习二叉树(BinaryTree)(纯小白进)
目录: 一、 前言二、 正文2.1、 树的概念2.1.1、 树的结构2.1.2、 树的小知识 2.2、 认识二叉树2.2.1、 二叉树的概念2.2.2、 特殊的二叉树 2.3、 实现二叉树2.3.1、 结构2.3.2、 节点数2.3.3、 树深度2.3.4、 前、中、后序遍历 销毁2.3.4.1、 前序遍历2.3.4.2、 中…...
诗风秦韵诗词学习画廊宣言
诗风秦韵诗词学习画廊宣言 弘扬传统传承文明,奋斗路上不断前进,青春不朽梦想扬帆,华夏赞歌我心飞扬...
Cannot determine local hostname
1. 问题与解答 报错: o.s.cloud.commons.util.InetUtils : Cannot determine local hostname 可能原因: 缺少一个logback.xml 2. logback日志文件介绍 2.1 logback结构与组成 logback.xml 文件是 Logback 的核心配置文件,其基本…...
电工课堂-对晶闸管移相控制触发要求
晶闸管移相控制触发的要求主要包括触发信号的同步性、移相范围、输出功率、触发脉冲的参数和形式等。 触发信号的同步性:触发信号必须与主电路的电源频率保持一致,并具有固定的相位关系。这是为了确保在每个周期内晶闸管都能在相同的相位上被触发&#x…...
基于Arduino做的“鱿鱼游戏”BOSS面具,支持动作检测
这是一个结合了3D打印、舵机、PIR传感器和DFPlayer MP3模块的DIY项目,旨在制作一个带有动画眼睛的"鱿鱼游戏"老板面具。当检测到动作时,面具的眼睛会移动并播放声音,非常适合万圣节使用。 这个项目是一个很好的起点,特…...
数据库的查询操作
之前学习了怎么创建数据库,创建数据表以及给数据表添加数据,我们今天就学习一下数据的查询 一. 查询语句的语法 select 列名(字段名) form 表名 [where (查询条件表达式)] [order by <排序的列明>[…...
WebGL编程指南 - WebGL概述
WebGL,是一项用来在网页上绘制和渲染复杂三维图形(3D图形),并允许用户与之进行交互的技术 WebGL的一些信息: 表层基于HTML5标准,通过Canvas元素公开底层基于OpenGL,与OpenGL ES规范非常接近暂…...
前端杂学录(十)
1.axios 的底层实现 1. XMLHttpRequests 在浏览器环境中,Axios 使用 XMLHttpRequest 对象来发送请求。这是一个古老的 Web API,用于在浏览器中进行异步 HTTP 请求。 2. Node.js 的 http 模块 在 Node.js 环境中,Axios 使用 Node.js 的 ht…...
C++上机|编写函数invert实现对一维数组的倒序
//编写函数invert实现对一维数组的倒序 # include <iostream> using namespace std;class invert_array {private://int a[10]{0,1,2,3,4,5,6,7,8,9};public: void invert(int A[], int n){int i,j,temp;int m (n-1)/2;for(i0;i<m;i){jn-1-i;tempA[i];A[i]A[j];A[j]t…...
使用LSPatch+PlusNE修改手机软件
一、问题概述 国内使用一些软件,即使科学上网,打开都是网络错误,更换节点同样如此。 二、软件下载 通过官网或者正规商店(如Google play)下载并且安装。 是的,先要下载一个无法使用的版本,后续对其进行修改。 三、下…...
基于springboot的4S店车辆管理系统
作者:计算机学长阿伟 开发技术:SpringBoot、SSM、Vue、MySQL、ElementUI等,“文末源码”。 系统展示 【2024最新】基于JavaSpringBootVueMySQL的,前后端分离。 开发语言:Java数据库:MySQL技术:…...
C++从入门到起飞之——(multi)set与(multi)map的的使用 全方位剖析!
🌈个人主页:秋风起,再归来~🔥系列专栏:C从入门到起飞 🔖克心守己,律己则安 目录 1. 序列式容器和关联式容器 2. set系列的使⽤ 2.1 set和multiset参考⽂档 2.2 set类的介绍 2.3 se…...
HTML5实现古典音乐网站源码模板2
文章目录 1.设计来源1.1 主界面1.2 古典音乐界面1.3 著名人物界面1.4 古典乐器界面1.5 历史起源界面1.6 联系我们界面 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板,程序开发,在线开发,在线沟通 作者:xcLeigh 文章地址&a…...
基于SpringBoot+Vue+uniapp的诗词学习系统的详细设计和实现
详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念,提供了一套默认的配置,让开发者可以更专注于业务逻辑而不…...
基于SpringBoot网上超市的设计与实现(论文+源码)_kaic
摘 要 网络技术和计算机技术发展至今,已经拥有了深厚的理论基础,并在现实中进行了充分运用,尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代,所以对于信息的宣传和管理就很关键。因此超市商品销售信…...
《webpack深入浅出系列》
webpack深入浅出系列 ES6模块与CommonJS模块的主要区别 加载时机:ES6模块是编译时输出,即模块在编译阶段就已经确定了依赖关系;而CommonJS模块是运行时才加载,即运行到某个require语句时才加载对应的模块。 (也就是说…...
云服务器使用挂载的数据盘空间(自用)
最近在使用浪潮云服务器的时候遇到系统盘存储空间全部使用完了,而浪潮提供的服务器配置里面还有数据盘空间,但是在使用df -h无法查看到数据盘的相关信息,查找后才发现是因为新开服务器没有对数据盘进行挂载,因此无法使用。在网上找…...
snmp usm OID
在Java中,SNMP(简单网络管理协议)是一种用于网络管理的互联网标准协议。它允许网络管理员从中央位置监控网络设备,如服务器、工作站、路由器、交换机和打印机等。SNMP通过允许这些设备报告关于它们状态的信息,从而帮助…...
数据仓库分层设计概念
数据仓库分层设计是一种结构化方法,用于组织和管理数据仓库中的数据。这种设计方法通过将数据从原始数据逐步转换为满足业务分析需求的结构化数据,提高了数据处理效率、数据质量和一致性。数据仓库分层设计的主要目的包括支持数据的重用、优化性能、提高…...
【HTML】defer 和 async 属性在 script 标签中分别有什么作用?
需要这两个属性的原因? 首先我们要知道的是,浏览器在解析 HTML 的过程中,遇到了 script 元素是不能继续构建 DOM 树的。 它会停止解析构建,首先去下载 js 代码,并且执行 js 的脚本;只有在等到 js 脚本执行…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...
处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...
