【数据结构】二叉树

在这里插入图片描述

🐇

🔥博客主页: 云曦
📋系列专栏:数据结构

💨吾生也有涯,而知也无涯
💛 感谢大家👍点赞 😋关注📝评论

文章目录

  • 前言
  • 一、树的概念及结构
    • 🌳1.1 树的概念
    • 🌳1.4 树和非树
    • 🌳1.3 树的表示
    • 🌳1.4 树在实际中的运用
  • 二、二叉树的概念及结构
    • 🌳2.1 二叉树的概念
    • 🌳2.2 现实中的二叉树
    • 🌳2.3 特殊的二叉树
    • 🌳2.4 二叉树的性质
    • 🌳2.5 二叉树的存储结构
      • ☘️2.5.1 顺序存储
      • ☘️2.5.2 链式存储
  • 三、二叉树链式结构及实现
    • 🌳3.1 二叉树的遍历
      • ☘️3.1.1 二叉树前序、中序、后序遍历的规则
      • ☘️3.1.2 前序遍历
      • ☘️3.1.3 中序遍历
      • ☘️3.1.4 后序遍历
      • ☘️3.1.5 层序遍历
    • 🌳3.2 二叉树节点个数的统计
      • ☘️3.2.1 节点的个数
      • ☘️3.2.2 叶子节点的个数
    • 🌳3.3 二叉树的创建和销毁
      • ☘️3.3.2二叉树的创建
      • ☘️3.3.2 二叉树的销毁
    • 🌳3.3 二叉树接口测试
  • 四、完整代码
    • 🌳<font color=Red>**4.1 BinaryTree.h**
    • 🌳<font color=Red>**4.2 BinaryTree.c**
    • 🌳<font color=Red>**4.3 test.c**

前言

在上期,讲解完栈和队列的实现后,本期迎来了新的知识,名为"二叉树",希望大家能坚持的学习下去。

一、树的概念及结构

🌳1.1 树的概念

树跟之前所学的顺序表、链表等不相同,树是一种非线性 的数据结构,它由n(n>=0)个有序节点组成一个具有层次关系的集合。把它叫作树是因为它看起来像一颗倒挂的树,也就是根朝上,而叶子朝下

  • 有一个特殊的节点,称作根节点,根节点没有前驱节点。
  • 除根节点外,其余结点被分成M(M>0)个互不相交的集T1T2、……、Tm,其中每一个集合Ti(1<= i<= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继
  • 因此树是由递归定义
    在这里插入图片描述
  • 树的相关概念:
    在这里插入图片描述
  1. 节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6
  2. 叶节点或终端节点:度为0的节点称为叶节点; 如上图:B、C、H、I…等节点为叶节点
  3. 非终端节点或分支节点:度不为0的节点; 如上图:D、E、F、G…等节点为分支节点
  4. 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点
  5. 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点
  6. 兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点
  7. 树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6
  8. 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
  9. 树的高度或深度:树中节点的最大层次; 如上图:树的高度为4
  10. 堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:H、I互为兄弟节点
  11. 节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先
  12. 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙
  13. 森林:由m(m>0)棵互不相交的树的集合称为森林;

🌳1.4 树和非树

注意:树形结构中,子树之间是没有交集的,否则就不是树形结构了。
在这里插入图片描述

🌳1.3 树的表示

孩子兄弟表示法:

typedef int DataType;typedef struct TreeNode
{struct TreeNode* firstchild;//第一个孩子节点struct TreeNode* nextbrother;//指向下一个兄弟节点DataType data;//节点的数据域
}TNode;

🌳1.4 树在实际中的运用

用于表示文件系统的目录数结构
在这里插入图片描述

二、二叉树的概念及结构

🌳2.1 二叉树的概念

每一颗二叉树是节点的一个有序的集合,该集合的特点是:

  1. 由一个根和左子树、右子树的组成的二叉树。
  2. 该树也有可能为空。

在这里插入图片描述
从上图可以看出:

  1. 二叉树不存在大于2的节点。
  2. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树。
  • 注意:对于任何一颗二叉树都有可能由以下几种复合而成的:
    在这里插入图片描述

🌳2.2 现实中的二叉树

在这里插入图片描述

🌳2.3 特殊的二叉树

  1. 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是 ,则它就是满二叉树。
  2. 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。
    在这里插入图片描述

🌳2.4 二叉树的性质

  1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有 个结点.
  2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是 .
  3. 对任何一棵二叉树, 如果度为0其叶结点个数为 , 度为2的分支结点个数为 ,则有 = +1
  4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h= . (ps: 是log以2为底,n+1为对数)
  5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:
  • 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
  • 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
  • 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

🌳2.5 二叉树的存储结构

☘️2.5.1 顺序存储

顺序结果存储就是用数组来存储的,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而在使用时只有堆才会用数组来存储,所以本期暂时不讲解顺序存储。

☘️2.5.2 链式存储

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。链式结构又分为二叉链和三叉链,当前我们使用的都是二叉链,三叉链会在讲解红黑树时使用。

typedef char BTDataType;
//二叉链
typedef struct BinaryTreeNode
{struct BinaryTreeNode* left;//指向当前节点左孩子struct BinaryTreeNode* right;//指向当前节点右孩子BTDataType data;//当前节点值域
}BTNode;//三叉链
typedef struct BinaryTreeNode
{struct BinaryTreeNode* parents;//指向当前节点的双亲struct BinaryTreeNode* left;//指向当前节点左孩子struct BinaryTreeNode* right;//指向当前节点右孩子BTDataType data;//当前节点值域
}BTNode;

三、二叉树链式结构及实现

结构的创建

typedef char BTDataType;typedef struct BinaryTreeNode
{struct BinaryTreeNode* left;//左子树struct BinaryTreeNode* right;//右子树BTDataType data;//节点的数据域
}BTNode;

🌳3.1 二叉树的遍历

学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的节点进行相应的操作,并且每个节点只操作一次

☘️3.1.1 二叉树前序、中序、后序遍历的规则

  • 前序遍历:先访问根节点,其次是左子树,最后是右子树(根 -> 左子树 -> 右子树)
  • 中序遍历:先访问左子树,其次是根,最后是右子树(左子树 -> 根 -> 右子树)
  • 后序遍历:先访问左子树,其次是右子树,最后是根(左子树 -> 右子树 -> 根)
  • 举例:
    在这里插入图片描述

由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为
根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。

// 二叉树前序遍历
void PreOrder(BTNode* root);
// 二叉树中序遍历
void InOrder(BTNode* root);
// 二叉树后序遍历
void PostOrder(BTNode* root);

☘️3.1.2 前序遍历

//二叉树前序遍历
void PrevOrder(BTNode* root)
{//根为空就返回if (root == NULL){printf("NULL ");return;}//根 -> 左子树 -> 右子树printf("%c ", root->data);//打印根PrevOrder(root->left);//递归左子树PrevOrder(root->right);//递归右子树
}

☘️3.1.3 中序遍历

//二叉树中序遍历
void InOrder(BTNode* root)
{//根为空就返回if (root == NULL){printf("NULL ");return;}//左子树 -> 根 -> 右子树InOrder(root->left);//递归左子树printf("%c ", root->data);//打印根InOrder(root->right);//递归右子树
}

☘️3.1.4 后序遍历

void PostOrder(BTNode* root)
{//根为空就返回if (root == NULL){printf("NULL ");return;}//左子树 -> 右子树 -> 根PostOrder(root->left);//递归左子树PostOrder(root->right);//递归右子树printf("%c ", root->data);//打印根
}

☘️3.1.5 层序遍历

  • 前序中序后序其实也叫:深度优先遍历
  • 而层序遍历也叫作:广度优先遍历
  • 层序的核心思路就是:上层取出的时候,带下一层进
  • 层序遍历需要用到队列来实现,而在C语言中没有队列的库,那么还要实现一个队列。但其实不需要实现,因为上一起已经实现过了,我们直接将源文件和头文件复制粘贴到实现二叉树的目录下即可。(实现栈和队列的链接)
  • 实现思路:在这里插入图片描述
    注意:引用队列的源文件和头文件后,要在队列的头文件里声明树的结构体,然后将队列结构data的类型改为树的结构体指针类型
    在这里插入图片描述
    且在二叉树的头文件里声明队列的头文件时,要在树的结构体后面声明,因为在编译是头文件是张开向上找结构体的。
    在这里插入图片描述
void LevelOrder(BTNode* root)
{//创建及初始化队列Que q;QueueInit(&q);//空树就不需要入队列了//不是空树就把根节点入队列if (root){QueuePush(&q, root);}while (!QueueEmpty(&q)){//根节点出队列BTNode* front = QueueFront(&q);QueuePop(&q);printf("%c ", front->data);//左子树入队列if (front->left){QueuePush(&q, front->left);}//右子树入队列if (front->right){QueuePush(&q, front->right);}}printf("\n");QueueDestroy(&q);
}

🌳3.2 二叉树节点个数的统计

☘️3.2.1 节点的个数

int TreeSize(BTNode* root)
{return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

看递归很绕的时候教大家一个方法,画递归展开图
函数递归展开图

☘️3.2.2 叶子节点的个数

int LeafSize(BTNode* root)
{//根为空就返回0if (root == NULL){return 0;}//左右子树为空,则返回1if (root->left == NULL && root->right == NULL){return 1;}//递归左子树的叶子个数加递归右子树的叶子个数return LeafSize(root->left) + LeafSize(root->right);
}

相当于节点个数功能的思路延伸,根为空返回0,左子树与右子树都为空返回1,最后递归左右子树相加就得到了叶子节点的个数。

🌳3.3 二叉树的创建和销毁

☘️3.3.2二叉树的创建

  • 二叉树的创建思路是:通过前序遍历的数组"ABD##E##C##"构建二叉树
  • 只有前序是不可能构建出二叉树的,但是在数组里用’#'表示NULL,这样构建二叉树就很容易了。
    在这里插入图片描述
BTNode* BinaryTreeCreate(BTDataType* s, int* pi)
{//遇到'#',加加pi,然后返回NULLif (s[*pi] == '#'){(*pi)++;return NULL;}//malloc出来新的根节点BTNode* root = (BTNode*)malloc(sizeof(BTNode));if (root == NULL){perror("malloc fail");exit(-1);}root->data = s[*pi];(*pi)++;//递归构建左子树root->left = BinaryTreeCreate(s, pi);//递归构建右子树root->right = BinaryTreeCreate(s, pi);return root;
}

☘️3.3.2 二叉树的销毁

销毁的含义依然是:把空间还给操作系统。
销毁二叉树很简单,用后序遍历的思路,把打印数据改成free(释放)节点即可。

//思路就是:使用后序遍历思路销毁
void TreeDestroy(BTNode* root)
{//根为空时,直接返回if (root == NULL){return;}TreeDestroy(root->left);//递归左子树TreeDestroy(root->right);//递归右子树free(root);//释放根节点root = NULL;
}

🌳3.3 二叉树接口测试

int main()
{//构建树char str[] = "ABD##E##C##";int i = 0;BTNode* root = BinaryTreeCreate(str, &i);//测试功能PrevOrder(root);printf("\n");InOrder(root);printf("\n");PostOrder(root);printf("\n");int ATree = TreeSize(root);printf("%d\n", ATree);//5int BTree = TreeSize(root->left);printf("%d\n", BTree);//3int ALeaf = LeafSize(root);printf("%d\n", ALeaf);//3LevelOrder(root);//A B C D ETreeDestroy(root);return 0;
}

在这里插入图片描述

四、完整代码

🌳4.1 BinaryTree.h

#pragma once#include<stdio.h>
#include<stdlib.h>//二叉树
typedef char BTDataType;typedef struct BinaryTreeNode
{struct BinaryTreeNode* left;//左子树struct BinaryTreeNode* right;//右子树BTDataType data;//当前节点值域
}BTNode;#include "Queue.h"//二叉树前序遍历
void PrevOrder(BTNode* root);
//二叉树中序遍历
void InOrder(BTNode* root);
//二叉树后序遍历
void PostOrder(BTNode* root);
//二叉树的层次
//核心思路:上层取出的时候,带下一层进
void LevelOrder(BTNode* root);
//二叉树节点的个数
int TreeSize(BTNode* root);
//二叉树叶子的个数
int LeafSize(BTNode* root);
//二叉树的销毁
void TreeDestroy(BTNode* root);
//通过前序遍历的数组"ABD##E##C##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* s, int* pi);

🌳4.2 BinaryTree.c

#include "BinaryTree.h"void PrevOrder(BTNode* root)
{//根为空就返回if (root == NULL){printf("NULL ");return;}//根 -> 左子树 -> 右子树printf("%c ", root->data);//打印根PrevOrder(root->left);//递归左子树PrevOrder(root->right);//递归右子树
}void InOrder(BTNode* root)
{//根为空就返回if (root == NULL){printf("NULL ");return;}//左子树 -> 根 -> 右子树InOrder(root->left);//递归左子树printf("%c ", root->data);//打印根InOrder(root->right);//递归右子树
}void PostOrder(BTNode* root)
{//根为空就返回if (root == NULL){printf("NULL ");return;}//左子树 -> 右子树 -> 根PostOrder(root->left);//递归左子树PostOrder(root->right);//递归右子树printf("%c ", root->data);//打印根
}int TreeSize(BTNode* root)
{return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}int LeafSize(BTNode* root)
{//根为空就返回0if (root == NULL){return 0;}//左右子树为空,则返回1if (root->left == NULL && root->right == NULL){return 1;}//递归左子树的叶子个数加递归右子树的叶子个数return LeafSize(root->left) + LeafSize(root->right);
}//核心思路:上层取出的时候,带下一层进
void LevelOrder(BTNode* root)
{//创建及初始化队列Que q;QueueInit(&q);//空树就不需要入队列了//不是空树就把根节点入队列if (root){QueuePush(&q, root);}while (!QueueEmpty(&q)){//根节点出队列BTNode* front = QueueFront(&q);QueuePop(&q);printf("%c ", front->data);//左子树入队列if (front->left){QueuePush(&q, front->left);}//右子树入队列if (front->right){QueuePush(&q, front->right);}}printf("\n");QueueDestroy(&q);
}//思路就是:使用后序遍历思路销毁
void TreeDestroy(BTNode* root)
{//根为空时,直接返回if (root == NULL){return;}TreeDestroy(root->left);//递归左子树TreeDestroy(root->right);//递归右子树free(root);//释放根节点root = NULL;
}BTNode* BinaryTreeCreate(BTDataType* s, int* pi)
{//遇到'#',加加pi,然后返回NULLif (s[*pi] == '#'){(*pi)++;return NULL;}//malloc出来新的根节点BTNode* root = (BTNode*)malloc(sizeof(BTNode));if (root == NULL){perror("malloc fail");exit(-1);}root->data = s[*pi];(*pi)++;//递归构建左子树root->left = BinaryTreeCreate(s, pi);//递归构建右子树root->right = BinaryTreeCreate(s, pi);return root;
}

🌳4.3 test.c

#include "BinaryTree.h"int main()
{//构建树char str[] = "ABD##E##C##";int i = 0;BTNode* root = BinaryTreeCreate(str, &i);//测试功能PrevOrder(root);printf("\n");InOrder(root);printf("\n");PostOrder(root);printf("\n");int ATree = TreeSize(root);printf("%d\n", ATree);//5int BTree = TreeSize(root->left);printf("%d\n", BTree);//3int ALeaf = LeafSize(root);printf("%d\n", ALeaf);//3LevelOrder(root);TreeDestroy(root);return 0;
}

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

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

相关文章

【5G 核心网】5G 多PDU会话锚点技术介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

Spring Boot(六十四):SpringBoot集成Gzip压缩数据

1 实现思路 2 实现 2.1 创建springboot项目 2.2 编写一个接口,功能很简单就是传入一个Json对象并返回 package com.example.demo.controller;import com.example.demo.entity.Advertising; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframewo…

网络通信原理传输层TCP三次建立连接(第四十八课)

ACK :确认号 。 是期望收到对方的下一个报文段的数据的第1个字节的序号,即上次已成功接收到的数据字节序号加1。只有ACK标识为1,此字段有效。确认号X+1SEQ:序号字段。 TCP链接中传输的数据流中每个字节都编上一个序号。序号字段的值指的是本报文段所发送的数据的第一个字节的…

「UG/NX」Block UI 面收集器FaceCollector

✨博客主页何曾参静谧的博客📌文章专栏「UG/NX」BlockUI集合📚全部专栏「UG/NX」NX二次开发「UG/NX」BlockUI集合「VS」Visual Studio「QT」QT5程序设计「C/C+&#

LangChain手记 Question Answer 问答系统

整理并翻译自DeepLearning.AILangChain的官方课程&#xff1a;Question Answer&#xff08;源代码可见&#xff09; 本节介绍使用LangChian构建文档上的问答系统&#xff0c;可以实现给定一个PDF文档&#xff0c;询问关于文档上出现过的某个信息点&#xff0c;LLM可以给出关于该…

【vue】项目基础环境搭建、css样式重置与公用

nodejs环境 nodejs是当下前端工程化开发必不可少的环境, 使用 nodejs的 npm功能来管理依赖包 查看node 和 npm的版本 node -v #查看node版本npm -v #查看npm版本 git版本控制 git版本控制工具是目前最为流行的分布式版本管理工具,代码的**提交, 检出, 日志**, 都需要通过git完…

Matplotlib数据可视化(二)

目录 1.rc参数设置 1.1 lines.linestype取值 1.2 lines.marker参数的取值 1.3 绘图中文预设 1.4 示例 1.4.1 示例1 1.4.2 示例2 1.rc参数设置 利用matplotlib绘图时为了让绘制出的图形更加好看&#xff0c;需要对参数进行设置rc参数设置。可以通过以下代码查看matplotli…

[Machine Learning] decision tree 决策树

&#xff08;为了节约时间&#xff0c;后面关于机器学习和有关内容哦就是用中文进行书写了&#xff0c;如果有需要的话&#xff0c;我在目前手头项目交工以后&#xff0c;用英文重写一遍&#xff09; &#xff08;祝&#xff0c;本文同时用于比赛学习笔记和机器学习基础课程&a…

【算法学习】两数之和II - 输入有序数组

题目描述 原题链接 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] &#xff0c;则 1 < index1 < …

Springboot MultipartFile文件上传与下载

yml文件配置是否可以上传及上传附件大小 servlet:multipart:# 允许文件上传enabled: true# 单个文件大小max-file-size: 20MB# 设置总上传的文件大小max-request-size: 50MB /*** param files* param request* Description 上传文件* Throws* Return java.util.List* Date 202…

动手学深度学习—卷积神经网络LeNet(代码详解)

1. LeNet LeNet由两个部分组成&#xff1a; 卷积编码器&#xff1a;由两个卷积层组成&#xff1b;全连接层密集块&#xff1a;由三个全连接层组成。 每个卷积块中的基本单元是一个卷积层、一个sigmoid激活函数和平均汇聚层&#xff1b;每个卷积层使用55卷积核和一个sigmoid激…

LeetCode--HOT100题(35)

目录 题目描述&#xff1a;23. 合并 K 个升序链表&#xff08;困难&#xff09;题目接口解题思路1代码解题思路2代码 PS: 题目描述&#xff1a;23. 合并 K 个升序链表&#xff08;困难&#xff09; 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合…

UDP 的报文结构以及注意事项

UDP协议 1.UDP协议端格式 1.图中的16位UDP长度,表示整个数据报(UDP首部UDP数据)的最大长度 2.若校验和出错,会直接丢弃 2.UDP的报文结构 UDP报文主体分为两个部分:UDP报头(占8个字节)UDP载荷/UDP数据 1.源端口号 16位,2个字节 2.目的端口号 16位,2个字节 3.包长度 指示了…

sd-webui安装comfyui扩展

文章目录 导读ComfyUI 环境安装1. 安装相关组件2. 启动sd-webui3. 访问sd-webui 错误信息以及解决办法 导读 这篇文章主要给大家介绍如何在sd-webui中来安装ComfyUI插件 ComfyUI ComfyUI是一个基于节点流程式的stable diffusion的绘图工具&#xff0c;它集成了stable diffus…

什么是闭包(closure)?为什么它在JavaScript中很有用?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 闭包&#xff08;Closure&#xff09;是什么&#xff1f;⭐ 闭包的用处⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&…

windows10 安装WSL2, Ubuntu,docker

AI- 通过docker开发调试部署ChatLLM 阅读时长&#xff1a;10分钟 本文内容&#xff1a; window上安装ubuntu虚拟机&#xff0c;并在虚拟机中安装docker&#xff0c;通过docker部署数字人模型&#xff0c;通过vscode链接到虚拟机进行开发调试.调试完成后&#xff0c;直接部署在云…

变更通知在开源SpringBoot/SpringCloud微服务中的最佳实践

目录导读 变更通知在开源SpringBoot/SpringCloud微服务中的最佳实践1. 什么是变更通知2. 变更通知的场景分析3. 变更通知的技术方案3.1 变更通知的技术实现方案 4. 变更通知的最佳实践总结5. 参考资料 变更通知在开源SpringBoot/SpringCloud微服务中的最佳实践 1. 什么是变更通…

Ubuntu在自己的项目中使用pcl

1、建立一个文件夹&#xff0c;如pcl_demos&#xff0c;里面建立一个.cpp文件和一个cmake文件 2、打开终端并进入该文件夹下&#xff0c;建立一个build文件夹存放编译的结果并进入该文件夹 3、对上一级进行编译 cmake .. 4、生成可执行文件 make 5、运行该可执行文件 6、可视…

微服务中间件-分布式缓存Redis

分布式缓存 a.Redis持久化1) RDB持久化1.a) RDB持久化-原理 2) AOF持久化3) 两者对比 b.Redis主从1) 搭建主从架构2) 数据同步原理&#xff08;全量同步&#xff09;3) 数据同步原理&#xff08;增量同步&#xff09; c.Redis哨兵1) 哨兵的作用2) 搭建Redis哨兵集群3) RedisTem…

金融语言模型:FinGPT

项目简介 FinGPT是一个开源的金融语言模型&#xff08;LLMs&#xff09;&#xff0c;由FinNLP项目提供。这个项目让对金融领域的自然语言处理&#xff08;NLP&#xff09;感兴趣的人们有了一个可以自由尝试的平台&#xff0c;并提供了一个与专有模型相比更容易获取的金融数据。…