深入学习二叉树(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、 二叉树的概念

一棵二叉树是结点的一个有限集合,该集合:

  1. 或者为空
  2. 由一个根节点加上两棵别称为左子树和右子树的二叉树组成d

在这里插入图片描述

从上图看出:

  1. 二叉树不存在度大于2的结点
  2. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

二叉树会有以下几种情况复合而成的

在这里插入图片描述

2.2.2、 特殊的二叉树

在这里插入图片描述

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

以下两张神图,来源于网络:

在这里插入图片描述

如上图所示,这是一棵现实中的二叉树,我们看着很形象,也很容易理解 “二叉” 这个概念,不过计算机可不这样认为,在它眼中二叉树要么长这样 [1,2,3,4,5],要么长这样 1->2->3->4->5
没错,二叉树在计算机中可以有两种表示形式

  • 顺序结构
    • 即以数组的形式存储节点信息,这种结构一般用于存储完全二叉树
    • 比如接下来要学的,因为数组正好符合完全二叉树连续存储的要求
  • 链式结构
    • 即以链表的形式存储节点信息,这种结构可以用于所有二叉树,本文代码结构也是以链式为主
    • 二叉树普遍都是不规则的,数组难以满足节点分散这个要求

知道结构后还需加以规则限制,二叉树的规则有

  • 空树也可以看作二叉树
  • 任何一棵二叉树,都可以分为根、左子树、右子树
  • 二叉树中不存在度大于2的节点(度即当前节点的子树数量)
  • 二叉树的子树有左右之分,顺序不可颠倒,即左边一定是左树

了解以上关于二叉树的相关性质,接下来,咱们来看一下关于二叉树的具体实现


2.3、 实现二叉树

这部分主要是实现一些简单功能,涉及大量递归知识。

2.3.1、 结构

前面说过,二叉树主要有两种表现形式,通常我们采用链式结构(链式二叉树)来实现。
任何一棵二叉树都有根、左、右三部分,细化到一个节点也是如此,因此链式二叉树在结构上分为以下三部分

  1. 数据域,负责存放当前节点的元素信息
  2. 左子树(左孩子),指向左树的指针
  3. 右子树(右孩子),指向右树的指针

二叉树的实现和创建如下:

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,同样的,需要借助递归,步骤如下

  • 设两个变量:leftHeightrightHeight ,分别用来存储左右子树的深度
  • 左右子树的深度即左右子树的节点数,统计方式与上面函数类型
  • 得到这两个深度后,判断谁是较大的一方,返回它
  • 这也是个典型的递归,终止条件为节点为空,接近手段为向下移动
    这个的代码量也很少,无非就是比上面多了两句
//二叉树的深度
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;
}

三、总结

以上就是二叉树的全部内容了,回顾全文,我们从介绍树的相关性质,到了解了二叉树的相关概念,学习了二叉树的基础功能和实现,相信你在看完本文后,一定能学到很多干货,轻松理解二叉树!,下一站:堆

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《数据结构》课程综合设计(zzu校园导航)(迪杰斯特拉算法)

一、系统&#xff08;问题&#xff09;描述 目前根据郑州大学主校区面积区域的广大&#xff0c;以及南、北核心教学楼的教室分布密集且较多&#xff1b;另外&#xff0c;多数地图软件无法精细导航到一个具体的地点&#xff0c;容易造成原地转圈的烦恼。但是&#xff0c;我们转…

js中map,filter,find,foreach的用法介绍

js中map&#xff0c;filter&#xff0c;find&#xff0c;foreach的用法介绍 在 JavaScript 中&#xff0c;数组提供了一些常用的迭代方法&#xff0c;如 map、filter、find 和 forEach&#xff0c;这些方法允许你对数组中的每个元素进行操作&#xff0c;下面是它们的用法和区别…

Python爬虫实战:利用青果代理IP获取跨境电商数据

文章目录 一、跨境电商数据的作用1.1 市场趋势预测与洞察1.2 消费者行为分析1.3 库存管理优化1.4 定价策略制定 二、爬取目标三、环境准备四、代理IP获取4.1 为什么爬虫要用代理IP&#xff1f;4.2 为什么选择青果代理IP&#xff1f;4.3 青果代理IP领取4.4 利用代码获取IP 五、爬…

excel 表格中url转图片

待处理的单元格通过如下公式获取目标格式&#xff1a; "<table><img src"&A4&" height20></table>" 然后下拉后获取多列的单元格转换结果&#xff0c; 然后将这些转换后的结果拷贝到纯文本文档中&#xff0c; 然后再将纯文本…

新基建下的园区智慧化变革 | 科技驱动未来开放式智慧园区

在数智化浪潮席卷之下&#xff0c;千行百业的数字化转型步伐加快。智慧园区建设借助创新的数字化、智能化技术&#xff0c;对园区内的人、机、物、事进行建模和重构&#xff0c;克服传统园区数据割裂、分散管理、无集成、体验差的问题&#xff0c;构建更智慧的管理方式、服务体…

unity学习-雾的渲染

在Light面板下的Other Settings中勾选fog就会让场景中生成雾气 Coloer&#xff1a;颜色 Mode&#xff1a;预设 Density&#xff1a;密度 当Mode调整为Linear模式会多出两个选项 Start&#xff1a;往前从多少米开始 End&#xff1a;到多少米有雾气 Start&#xff1a;设置…

[单master节点k8s部署]41.部署springcloud项目

在之前的文章中我们配置了mysql和harbor&#xff0c;现在我们可以将一个springcloud部署在k8s集群中了。 项目概述 这个springcloud项目将采用maven进行打包部署。首先安装maven&#xff1a; yum install java-1.8.0-openjdk maven-3.0.5* -y 然后将该项目上传到k8s集群的m…

c#编写的各类应用程序

001 课程简介&#xff0c;C# 语言简介&#xff0c;开发环境准备 (yuque.com)https://www.yuque.com/yuejiangliu/dotnet/timothy-csharp-001 一个Solution里包含多个Project 一、见识 C# 编写的各类应用程序 二、类库的引用&#xff08;黑/白盒引用&#xff09; 1、黑盒引用&a…

C++从入门到起飞之——(multi)set与(multi)map的的使用 全方位剖析!

&#x1f308;个人主页&#xff1a;秋风起&#xff0c;再归来~&#x1f525;系列专栏&#xff1a;C从入门到起飞 &#x1f516;克心守己&#xff0c;律己则安 目录 1. 序列式容器和关联式容器 2. set系列的使⽤ 2.1 set和multiset参考⽂档 2.2 set类的介绍 2.3 se…

打印自然常数E

自然常数E 自然常数&#xff0c;符号e&#xff0c;为数学中一个常数&#xff0c;是一个无限不循环小数&#xff0c;且为超越数&#xff0c;其值约为2.718281828459045。它是自然对数函数的底数。 我们打印表达式(11/x)的x次方的值以及获取第一次大于2.718的正整数 新建C#控制…

Linux系统:Ubuntu上安装Chrome浏览器

Ubuntu系统版本&#xff1a;23.04 在Ubuntu系统上安装Google Chrome浏览器&#xff0c;可以通过以下步骤进行&#xff1a; 终端输入以下命令&#xff0c;先更新软件源&#xff1a; sudo apt update 或 sudo apt upgrade终端输入以下命令&#xff0c;下载最新的Google Chrome .…

HarmonyNext保存Base64文件到Download下

本文介绍如何保存Base64的文件到Download下 参考文档地址&#xff1a; 保存用户文件-Harmony Next 用到的是DOWNLOAD模式保存文件 用户在使用save接口时&#xff0c;可以将pickerMode配置为DOWNLOAD模式&#xff0c;该模式下会拉起授权接口&#xff0c;用户确认后会在公共路径…

net core 微信公众号发送模板消息完整实现

第一完整看一下微信官方的文档 链接&#xff1a;开发前必读 / 首页 (qq.com) 想要发送模板消息分为一下几步 第一步&#xff1a;想要发消息需要有这几个参数&#xff0c; openid&#xff0c;这是给谁发消息 access_token&#xff0c;调用接口必要的 appid、secret 这两个是生…

如何替换OCP节点(二):使用 antman脚本 | OceanBase应用实践

前言&#xff1a; OceanBase Cloud Platform&#xff08;简称OCP&#xff09;&#xff0c;是 OceanBase数据库的专属企业级数据库管理平台。 在实际生产环境中&#xff0c;OCP的安装通常是第一步&#xff0c;先搭建OCP平台&#xff0c;进而依赖OCP来创建、管理和监控我们的生…

开放式蓝牙耳机哪个品牌好用?开放式耳机排行榜测评!

开放式耳机&#xff0c;因其特殊的不入耳佩戴模式&#xff0c;让使用者在享受音乐或者进行通话的过程中&#xff0c;依然可以对外界声音保持敏感。在户外运动场景下&#xff0c;这种特性优势尽显&#xff0c;既保证了耳机佩戴的稳定和舒适&#xff0c;又提高了运动的安全性。为…

如何做好项目管理,实现高效协作?

项目管理难&#xff0c;难于上青天&#xff01; 小卫&#xff0c;某服装生产企业项目经理&#xff0c;说到项目难管理&#xff0c;他有话要说&#xff1a; 做项目&#xff0c;看似简单&#xff0c;不同部门各司其职&#xff0c;但也正因为涉及跨部门协作&#xff0c;管理难度也…

Qt:图片文字转base64程序

目录 一.Base64 1.编码原理 2.应用场景 3.优点 4.限制 5.变种 二.文字与Base64互转 1.ui设计 2.文字转Base64 3.Base64转文字 三.图片与Base64互转 1.ui设计 2.选择图片与图片路径 3.图片转Base64 4.Base64转图片 四.清空设置 五.效果 六.代码 base64conver…

基于SpringBoot+Vue+uniapp的时间管理小程序的详细设计和实现(源码+lw+部署文档+讲解等)

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…

大厂面试一上来就手撕 Transformer,心凉半截

在这两年&#xff0c;尤其是大模型问世之后&#xff0c;有关 Transformer 的面试题不仅数量众多&#xff0c;而且颇具新意。 今日&#xff0c;我将分享 18 道 Transformer 高频面试题&#xff08;如需获取更多专业面试题&#xff0c;扫描文末二维码即可&#xff09;&#xff0…

关于为什么蒸馏后的小模型和一开始的小模型的区别是什么?

起初&#xff0c;我想写这个博客是因为无意间看到了一个采访&#xff0c;无意间浏览才发现这段说的给我一种恍然大悟的感觉。 主持人提问&#xff1a;训练一个大模型&#xff0c;然后再将其压缩蒸馏成一个小模型&#xff0c;那和直接训练一个小模型&#xff0c; 这两者的区别是…