数据结构进阶篇 之 【二叉树顺序存储(堆)】的整体实现讲解(赋完整实现代码)

在这里插入图片描述

做人要谦虚,多听听别人的意见,然后记录下来,看看谁对你有意见

一、二叉树的顺序(堆)结构及实现

1.二叉树的顺序结构

2.堆的概念及结构

3.堆的实现

3.1 向下调整算法 AdJustDown

3.2 向上调整算法 AdJustUP

3.3 堆的创建

3.3.1 向上建堆
3.3.2 向下建堆
3.3.3 堆的初始化与销毁
3.3.4 堆的插入(压栈)
3.3.5 取堆顶的数据
3.3.6 堆的删除
3.3.7 堆的数据个数
3.3.8 堆的判空

二、堆的完整实现代码

三、完结撒❀

–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–

一、二叉树的顺序(堆)结构及实现

1.二叉树的顺序结构


物理结构:数组
逻辑结构:二叉树

顺序结构存储就是使用数组来存储普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费,而完全二叉树更适合使用顺序结构存储

可能有些同学不太清楚普通二叉树使用数组来存储为什么会造成空间上的浪费,这里给大家讲解一下:
我们使用数组进行二叉树的存储时,父子节点之间需要满足的关系为

parent = (child+1)/2;
leftchild = parent2-1;
rightchild = parent
2+2;
ps:parent指父节点在数组中的下标位置,leftchild指左子节点在数组中的下标位置,rightchild指右子节点在数组中的下标位置

那么对于满二叉树和完全二叉树,我们按照一层一层(层序)往数组中进行存储。
举例如下图所示,大家可以按照下图简单计算验证一下父子之间是否满足父子关系:
在这里插入图片描述

可以知道,对于满二叉树和完全二叉树进行层序存储在数组中,按照下标计算都是满足上面所述的父子关系。

而对于普通二叉树(非满二叉树,非完全二叉树),我们依然按照上面存储进行计算
在这里插入图片描述
可以发现不符合父子节点之间的关系,问题在于2节点的右节点为空,而在存储时对于空节点我们并没有在数组中进行存储记录,相当于在数组中少了一个位置,那么我们如果把空节点加上,如下图:
在这里插入图片描述
这样就满足了父子间的关系,但是对于下标为4的位置并没有存储数据,就造成了空间浪费。

所以,对于普通二叉树我们一般使用链式结构进行存储,避免空间浪费。

现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

2.堆的概念及结构

如果有一个关键码的集合K = {K0,K1,K2,…,Kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki<=K2i+1且Ki<=K2i+2(Ki>=K2i+1且Ki>=K2i+2)i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆的性质:

1.堆中某个节点的值总是不大于或不小于其父节点的值;
2.堆总是一棵完全二叉树;

在这里插入图片描述
堆的兄弟节点(同一父节点的子两个子节点)之间是不论大小的,而对于小堆其父节点的值一定小于子节点,对于大堆其父节点的值一定大于子节点。

3.堆的实现

堆初始化结构:

//堆初始化
void HPInit(HP* php)
{assert(php);php->a = NULL;php->capacity = php->size = 0;
}

在给定一个数组去实现成堆之前我们需要先了解内部实现的核心逻辑

3.1 向下调整算法 AdJustDown

现在我们给出一个数组,逻辑上看做一颗完全二叉树。

int arr[] = {27,15,19,18,28,34,65,49,25,37}

我们通过从根节点开始的向下调整算法可以把它调整成一个小堆
向下调整算法有一个前提:左右子树必须是一个堆,才能调整。
上面数组逻辑上的二叉树可画为:
在这里插入图片描述
可以看出来,根节点27影响了整体的小堆结构,那么我们如何将其转变为小堆呢?
在这里插入图片描述

(制作不是很好大家将就着看看就行)
按照上面图片显示的流程,我们在逻辑上就把之前的二叉树变成了小堆排序,而其逻辑实现思想就是向下调整。

向下调整

再强调一边:
向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

从根开始,比较其子节点的大小,如果为大堆排序就将父节点与子节点中较大的节点交换,如果为小堆就将父节点与子节点中较小的节点交换。交换完毕继续重复以上逻辑,直到父节点大于子节点(大堆)或是父节点小于子节点(小堆)即可完成堆排序。

代码实现:

void Swap(HPDataType* px, HPDataType* py)
{HPDataType tmp = *px;*px = *py;*py = tmp;
}//向下调整O(logN)
void AdJustDown(HPDataType* a, int n, int parent)
{//从左孩子开始,child为小孩子那个int child = parent * 2 + 1;while (child<n){if (child + 1 < n && a[child] > a[child + 1]){++child;}if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[parent], &a[child]);parent = child;child = child * 2 + 1;}else{break;}}
}

3.2 向上调整算法 AdJustUP

在一个二叉树的数组中如果我们尾插了一个数据,可能就导致结构不再是堆。

所以我们如果是在现有的一个堆里进行数据尾插存储,那么我们要保证数据插入后还是堆,这时一般使用向上调整算法。

下面我们给出一个数组,请画出其逻辑结构二叉树:

int arr[] = {10,15,56,25,30,70}

二叉树:

在这里插入图片描述
如果我将5尾插在数组当中,那么就相当于是将56节点的右孩子连了一个5节点:
在这里插入图片描述
这显然已经不是小堆了,调整逻辑如下:
在这里插入图片描述
这就是向上调整的整体逻辑:

如果是进行小堆排序,将尾节点值与其父节点的值进行比较,如果小于父节点就交换,如果进行大堆,那就判断子节点是否大于父节点,若是大于就交换。

代码实现:

void Swap(HPDataType* px, HPDataType* py)
{HPDataType tmp = *px;*px = *py;*py = tmp;
}//向上调整 O(logN)
void AdJustUP(HPDataType* a, int child)
{int parent = (child - 1) / 2;//while (1)严格来说不行while(child>0){if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[child], &a[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}

向下调整算法和向上调整算法的时间复杂度都为O(logN),大家感兴趣可以算一下。

3.3 堆的创建

向上调整和向下调整都是基于已经形成了堆上面,那么如果随便给一个本就不是堆的数组,我们该如何进行建堆呢?

3.3.1 向上建堆

下面我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个小堆,现在我们通过算法,把它构建成一个小堆。

int a[] = {536821};

根节点左右子树不是小堆,我们怎么调整呢?

这里我们从根的左孩子节点开始向上调整,根据数组存储顺序向后以此执行,直到最后一个节点为止。

其二叉树为:
在这里插入图片描述
调整逻辑:
在这里插入图片描述
从根节点的子节点开始,进行向上调整,一次调整完毕将子节点对应数组下标加1进入下一个节点进行向上调整,直到除了根的所有节点都调整完毕,二叉树便变成了堆。

代码实现:

//向上调整 O(logN)
void AdJustUP(HPDataType* a, int child)
{int parent = (child - 1) / 2;//while (1)严格来说不行while(child>0){if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[child], &a[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}//初始化建堆
void HPInitArray(HP* php, HPDataType* a, int n)
{assert(php);php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);if (php->a == NULL){perror("malloc fail");return;}memcpy(php->a, a, sizeof(HPDataType) * n);php->size = php->capacity = n;//向上建堆 O(N*logN)for (int i = 1; i < php->size; i++){AdjustUp(php->a, i);}
}
3.3.2 向下建堆

向下建堆就是根据向下调整的逻辑进行。

我们把二叉树分为其根和子树,再把子树分为其根和子树,将每一个分好的子树都进行向下调整,直到叶子节点为止。

我们还拿上面数组为例:

int a[] = {536821};

这里我们从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成小堆

调整逻辑:在这里插入图片描述
代码实现:

//向下调整O(logN)
void AdJustDown(HPDataType* a, int n, int parent)
{//从左孩子开始,child为小孩子那个int child = parent * 2 + 1;while (child<n){//假设法选出左右节点中大/小的节点if (child + 1 < n && a[child] > a[child + 1]){++child;}if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[parent], &a[child]);parent = child;child = child * 2 + 1;}else{break;}}
}//初始化建堆
void HPInitArray(HP* php, HPDataType* a, int n)
{assert(php);php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);if (php->a == NULL){perror("malloc fail");return;}memcpy(php->a, a, sizeof(HPDataType) * n);php->size = php->capacity = n;//向下建堆 O(N)for (int i = (php->size - 1 - 1) / 2; i >= 0; i--){AdJustDown(php->a, php->size, i);}
}

向上建堆和向下建堆的时间复杂度分别为O(N*logN),O(N)。
因为向下建堆的时间复杂度小,所以我们在实际工作中进行建堆一般是选择向下建堆

3.3.3 堆的初始化与销毁

在数据结构中,创建任何结构,都需要对其进行初始化和销毁。

代码实现:

//堆初始化
void HPInit(HP* php)
{assert(php);php->a = NULL;php->capacity = php->size = 0;
}//堆销毁
void HPDestory(HP* php)
{assert(php);free(php->a);php->a = NULL;php->capacity = php->size = 0;
}
3.3.4 堆的插入(压栈)

插入一个数到数组的尾上,再进行向上调整算法,直到满足堆。
代码实现:

//向上调整 O(logN)
void AdJustUP(HPDataType* a, int child)
{int parent = (child - 1) / 2;//while (1)严格来说不行while(child>0){if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[child], &a[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}//压栈 O(logN)
void HPPush(HP* php, HPDataType x)
{assert(php);//判断空间是否足够if (php->size == php->capacity){int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, newcapacity * sizeof(HPDataType));if (tmp == NULL){perror("realloc fail");return;}php->a = tmp;php->capacity = newcapacity;}php->a[php->size] = x;php->size++;//数据尾插向上调整AdJustUP(php->a, php->size-1);
}
3.3.5 取堆顶的数据

在建好的堆中返回其根部数据。
代码实现:

//返回根数据
HPDataType HPTop(HP* php)
{assert(php);assert(php->size);return php->a[0];
}
3.3.6 堆的删除

删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。

代码实现:

//向下调整O(logN)
void AdJustDown(HPDataType* a, int n, int parent)
{//从左孩子开始,child为小孩子那个int child = parent * 2 + 1;while (child<n){if (child + 1 < n && a[child] > a[child + 1]){++child;}if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[parent], &a[child]);parent = child;child = child * 2 + 1;}else{break;}}
}//删除根数据O(logN)
void HPPop(HP* php)
{assert(php);assert(php->size);//将根数据与最后一个子叶交换,再删除最后一个数据Swap(&php->a[0], &php->a[php->size-1]);php->size--;//向下调整AdJustDown(php->a, php->size, 0);
}
3.3.7 堆的数据个数

代码实现:

int HeapSize(HP* php)
{assert(php);return php->size;
}
3.3.8 堆的判空

代码实现:

//判断堆是否为空
bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}

二、堆的完整实现代码

Heap.h:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>typedef int HPDataType;typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;//小堆//堆初始化
void HPInit(HP* php);
//初始化建堆
void HPInitArray(HP* php, HPDataType* a, int n);//堆销毁
void HPDestory(HP* php);//压栈
void HPPush(HP* php, HPDataType x);//返回根数据
HPDataType HPTop(HP* php);//删除根数据
void HPPop(HP* php);//堆的数据个数
int HPSize(HP* php);//判断堆是否为空
bool HPEmpty(HP* php);

Heap.c:

#include "Heap.h"//堆初始化
void HPInit(HP* php)
{assert(php);php->a = NULL;php->capacity = php->size = 0;
}//堆销毁
void HPDestory(HP* php)
{assert(php);free(php->a);php->a = NULL;php->capacity = php->size = 0;
}void Swap(HPDataType* px, HPDataType* py)
{HPDataType tmp = *px;*px = *py;*py = tmp;
}//向上调整 O(logN)
void AdJustUP(HPDataType* a, int child)
{int parent = (child - 1) / 2;//while (1)严格来说不行while(child>0){if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[child], &a[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}//压栈 O(logN)
void HPPush(HP* php, HPDataType x)
{assert(php);//判断空间是否足够if (php->size == php->capacity){int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, newcapacity * sizeof(HPDataType));if (tmp == NULL){perror("realloc fail");return;}php->a = tmp;php->capacity = newcapacity;}php->a[php->size] = x;php->size++;//数据尾插向上调整AdJustUP(php->a, php->size-1);
}//返回根数据
HPDataType HPTop(HP* php)
{assert(php);assert(php->size);return php->a[0];
}//向下调整O(logN)
void AdJustDown(HPDataType* a, int n, int parent)
{//从左孩子开始,child为小孩子那个int child = parent * 2 + 1;while (child < n){if (child + 1 < n && a[child] > a[child + 1]){++child;}if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[parent], &a[child]);parent = child;child = child * 2 + 1;}else{break;}}
}//删除根数据O(logN)
void HPPop(HP* php)
{assert(php);assert(php->size);//将根数据与最后一个子叶交换,再删除最后一个数据Swap(&php->a[0], &php->a[php->size-1]);php->size--;//向下调整AdJustDown(php->a, php->size, 0);
}int HeapSize(HP* php)
{assert(php);return php->size;
}//判断堆是否为空
bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}//初始化建堆
void HPInitArray(HP* php, HPDataType* a, int n)
{assert(php);php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);if (php->a == NULL){perror("malloc fail");return;}memcpy(php->a, a, sizeof(HPDataType) * n);php->size = php->capacity = n;//向上建堆 O(N*logN)/*for (int i = 1; i < php->size; i++){AdjustUp(php->a, i);}*///向下建堆 O(N)for (int i = (php->size - 1 - 1) / 2; i >= 0; i--){AdJustDown(php->a, php->size, i);}
}//建堆排序//排序
// 升序
//小堆时间复杂度太大O(N^2),用大堆进行排序O(N*logN)
//大堆//升序  大堆 O(N*logN)
//降序  小堆 O(N*logN)
void HeapSort(HPDataType* a, int n)
{//根据数组直接建堆 O(N)for (int i = (n - 1 - 1) / 2; i >= 0; --i){AdJustDown(a, n, i);}//交换根和尾的位置,删除尾,再向上调整 O(N*logN)int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdJustDown(a, end, 0);--end;}
}

三、完结撒❀

如果以上内容对你有帮助不妨点赞支持一下,以后还会分享更多编程知识,我们一起进步。
最后我想讲的是,据说点赞的都能找到漂亮女朋友❤
在这里插入图片描述

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

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

相关文章

C语言例1-8:设 char x,y; ,scanf(“x=%c,y=%c“,x,y); 后使 x 为 ‘X‘, y为 ‘Y‘,则键盘上的正确输入是

代码如下&#xff1a; #include<stdio.h> int main(void) {char x,y;scanf("x%c,y%c",&x,&y);printf("x%c,y%c\n",x,y);return 0; } 键盘输入选项A: xXyY 结果如下&#xff1a; 键盘输入选项B: xX,yY 结果如下&#xff1a; 键盘输入选项…

通过Jmeter准备压测数据-mysql示例

1、新建线程组 总共30万条数据 2、创建jdbc链接 创建jdbc连接配置 配置mysql连接 需要在jmeter安装的路径\apache-jmeter-5.6.3\lib\ext 目录下添加mysql 驱动 3、创建jdbc请求 jdbc链接名称需要与上一步中的保持一致&#xff0c;同时添加insert语句 例如 INSERT INTO test…

关系型数据库mysql(7)sql高级语句①

目录 一.MySQL常用查询 1.按关键字&#xff08;字段&#xff09;进行升降排序 按分数排序 &#xff08;默认为升序&#xff09; 按分数升序显示 按分数降序显示 根据条件进行排序&#xff08;加上where&#xff09; 根据多个字段进行排序 ​编辑 2.用或&#xff08;or&…

Python Flask框架 -- flask-migrate迁移ORM模型

# 之前使用的这个db.create_all()很有局限性&#xff0c;它不能把在class里修改的东西同步上数据库&#xff0c;所以不用了 # with app.app_context(): # 请求应用上下文 # db.create_all() # 把所有的表同步到数据库中去 例如&#xff0c;在User类中增加一个email字段&…

C语言例1-3:设 int a; ,语句 for(a=0;a==0;a++); 和语句 for(a=0;a=0;a++); 执行的循环次数分别是

答案&#xff1a;1,0 代码如下&#xff1a; #include<stdio.h> int main(void) {int a;for(a0;a0;a){printf("1\n");} return 0; } 结果如下&#xff1a; 代码如下&#xff1a; #include<stdio.h> int main(void) {int a;for(a0;a0;a){printf("…

【前端】layui学习笔记

参考视频&#xff1a;LayUI 1.介绍 官网&#xff1a;http://layui.apixx.net/index.html 国人16年开发的框架,拿来即用,门槛低 … 2. LayUi的安装及使用 Layui 是一套开源的 Web UI 组件库&#xff0c;采用自身轻量级模块化规范&#xff0c;遵循原生态的 HTML/CSS/JavaScript…

深入解析大语言模型显存占用:训练与推理

深入解析大语言模型显存占用&#xff1a;训练与推理 文章脉络 估算模型保存大小 估算模型在训练时占用显存的大小 全量参数训练 PEFT训练 估算模型在推理时占用显存的大小 总结 对于NLP领域的从业者和研究人员来说&#xff0c;有没有遇到过这样一个场景&#xff0c;你的…

C语言例1-11:语句 while(!a); 中的表达式 !a 可以替换为

A. a!1 B. a!0 C. a0 D. a1 答案&#xff1a;C while()成真才执行&#xff0c;所以!a1 &#xff0c;也就是 a0 原代码如下&#xff1a; #include<stdio.h> int main(void) {int a0;while(!a){a;printf("a\n");} return 0; } 结果如…

平台介绍-搭建赛事运营平台(8)

平台介绍-搭建赛事运营平台&#xff08;5&#xff09;提到了字典是分级的&#xff0c;本篇具体介绍实现。 平台级别的代码是存储在核心库中&#xff0c;品牌级别的代码是存储在品牌库中&#xff08;注意代码类是一样的&#xff09;。这部分底层功能封装为jar包&#xff0c;然后…

算法打卡day21(开始回溯)

今日任务&#xff1a; 1&#xff09;77.组合 77.组合 题目链接&#xff1a;77. 组合 - 力扣&#xff08;LeetCode&#xff09; 文章讲解&#xff1a;代码随想录 (programmercarl.com) 视频讲解&#xff1a;带你学透回溯算法-组合问题&#xff08;对应力扣题目&#xff1a;77…

Stable Diffusion之核心基础知识和网络结构解析

Stable Diffusion核心基础知识和网络结构解析 一. Stable Diffusion核心基础知识1.1 Stable Diffusion模型工作流程1. 文生图(txt2img)2. 图生图3. 图像优化模块 1.2 Stable Diffusion模型核心基础原理1. 扩散模型的基本原理2. 前向扩散过程详解3. 反向扩散过程详解4. 引入Late…

axios+springboot上传图片到本地(vue)

结果&#xff1a; 前端文件&#xff1a; <template> <div> <input type"file" id"file" ref"file" v-on:change"handleFileUpload()"/> <button click"submitFile">上传</button> </div&g…

3D汽车模型线上三维互动展示提供视觉盛宴

VR全景虚拟看车软件正在引领汽车展览行业迈向一个全新的时代&#xff0c;它不仅颠覆了传统展览的局限&#xff0c;还为参展者提供了前所未有的高效、便捷和互动体验。借助于尖端的vr虚拟现实技术、逼真的web3d开发、先进的云计算能力以及强大的大数据处理&#xff0c;这一在线展…

某东推荐的十大3C热榜第一名!2024随身wifi靠谱品牌推荐!2024随身wifi怎么选?

一、鼠标金榜&#xff1a;戴尔 商务办公有线鼠标 售价:19.9&#xffe5; 50万人好评 二、平板电脑金榜&#xff1a;Apple iPod 10.2英寸 售价:2939&#xffe5; 200万人好评 三、随身WiFi金榜&#xff1a;格行随身WiFi 售价:69&#xffe5; 15万人好评 四、游戏本金榜&#xff…

Android 自定义坐标曲线图(二)

Android 自定义坐标曲线图_android 自定义曲线图-CSDN博客 继上一篇文章&#xff0c;点击折线图上的点&#xff0c;显示提示信息进行修改&#xff0c;之前通过回调&#xff0c;调用外部方法&#xff0c;使用popupwindow或dialog来显示&#xff0c;但是这种方法对于弹框显示的位…

Mysql or与in的区别

创建一个表格 内涵一千万条数据 这张表中&#xff0c;只有id有建立索引&#xff0c;且其余都没有 测试1&#xff1a;使用or的情况下&#xff0c;根据主键进行查询 可以看到根据主键id进行or查询 花费了30-114毫秒&#xff0c;后面30多毫秒可能是因为Mysql的Buffer Pool缓冲池的…

Java并查集详解(附Leetcode 547.省份数量讲解)

一、并查集概念 并查集是一种树型的数据结构&#xff0c;用于处理一些不相交集合的合并及查询问题。 并查集的思想是用一个数组表示了整片森林&#xff08;parent&#xff09;&#xff0c;树的根节点唯一标识了一个集合&#xff0c;我们只要找到了某个元素的的树根&#xff0c;…

Unreal的Quixel Bridge下载速度过慢、下载失败

从Quixel Bridge下载MetaHuman模型&#xff0c;速度非常慢&#xff0c;而且经常下载失败&#xff0c;从头下载。 可以从Quixel Bridge的右上角我的图标->Support->Show Logs打开日志目录 downloaded-assets目录下为下载的资源 bridge-plugin.log文件记录了下载URL和下载…

Webpack生成企业站静态页面 - 项目搭建

现在Web前端流行的三大框架有Angular、React、Vue&#xff0c;很多项目经过这几年的洗礼&#xff0c;已经都 转型使用这三大框架进行开发&#xff0c;那为什么还要写纯静态页面呢&#xff1f;比如Vue中除了SPA单页面开发&#xff0c;也可以使用nuxt.js实现SSR服务端渲染&#x…

RabbitMQ基础笔记

视频链接&#xff1a;【黑马程序员RabbitMQ入门到实战教程】 文章目录 1.初识MQ1.1.同步调用1.2.异步调用1.3.技术选型 2.RabbitMQ2.1.安装2.1.1 Docker2.1.1 Linux2.1.1 Windows 2.2.收发消息2.2.1.交换机2.2.2.队列2.2.3.绑定关系2.2.4.发送消息 2.3.数据隔离2.3.1.用户管理2…