代码随想录算法训练营第六十天|Day60 图论

Bellman_ford 队列优化算法(又名SPFA)

https://www.programmercarl.com/kamacoder/0094.%E5%9F%8E%E5%B8%82%E9%97%B4%E8%B4%A7%E7%89%A9%E8%BF%90%E8%BE%93I-SPFA.html

本题我们来系统讲解 Bellman_ford 队列优化算法 ,也叫SPFA算法(Shortest Path Faster Algorithm)。

SPFA的称呼来自 1994年西南交通大学段凡丁的论文,其实Bellman_ford 提出后不久 (20世纪50年代末期) 就有队列优化的版本,国际上不承认这个算法是是国内提出的。 所以国际上一般称呼 该算法为 Bellman_ford 队列优化算法(Queue improved Bellman-Ford)

大家知道以上来历,知道 SPFA 和 Bellman_ford 队列优化算法 指的都是一个算法就好。

如果大家还不够了解 Bellman_ford 算法,强烈建议按照《代码随想录》的顺序学习,否则可能看不懂下面的讲解。

大家可以发现 Bellman_ford 算法每次松弛 都是对所有边进行松弛。

但真正有效的松弛,是基于已经计算过的节点在做的松弛。

给大家举一个例子:

本图中,对所有边进行松弛,真正有效的松弛,只有松弛 边(节点1->节点2) 和 边(节点1->节点3) 。

而松弛 边(节点4->节点6) ,边(节点5->节点3)等等 都是无效的操作,因为 节点4 和 节点 5 都是没有被计算过的节点。

所以 Bellman_ford 算法 每次都是对所有边进行松弛,其实是多做了一些无用功。

只需要对 上一次松弛的时候更新过的节点作为出发节点所连接的边 进行松弛就够了

基于以上思路,如何记录 上次松弛的时候更新过的节点呢?

用队列来记录。(其实用栈也行,对元素顺序没有要求)

#模拟过程

接下来来举例这个队列是如何工作的。

以示例给出的所有边为例:

5 6 -2
1 2 1
5 3 1
2 5 2
2 4 -3
4 6 4
1 3 5

1
2
3
4
5
6
7

我们依然使用minDist数组来表达 起点到各个节点的最短距离,例如minDist[3] = 5 表示起点到达节点3 的最小距离为5

初始化,起点为节点1, 起点到起点的最短距离为0,所以minDist[1] 为 0。 将节点1 加入队列 (下次松弛从节点1开始)


从队列里取出节点1,松弛节点1 作为出发点连接的边(节点1 -> 节点2)和边(节点1 -> 节点3)

边:节点1 -> 节点2,权值为1 ,minDist[2] > minDist[1] + 1 ,更新 minDist[2] = minDist[1] + 1 = 0 + 1 = 1 。

边:节点1 -> 节点3,权值为5 ,minDist[3] > minDist[1] + 5,更新 minDist[3] = minDist[1] + 5 = 0 + 5 = 5。

将节点2、节点3 加入队列,如图:


从队列里取出节点2,松弛节点2 作为出发点连接的边(节点2 -> 节点4)和边(节点2 -> 节点5)

边:节点2 -> 节点4,权值为1 ,minDist[4] > minDist[2] + (-3) ,更新 minDist[4] = minDist[2] + (-3) = 1 + (-3) = -2 。

边:节点2 -> 节点5,权值为2 ,minDist[5] > minDist[2] + 2 ,更新 minDist[5] = minDist[2] + 2 = 1 + 2 = 3 。

将节点4,节点5 加入队列,如图:


从队列里出去节点3,松弛节点3 作为出发点连接的边。

因为没有从节点3作为出发点的边,所以这里就从队列里取出节点3就好,不用做其他操作,如图:


从队列中取出节点4,松弛节点4作为出发点连接的边(节点4 -> 节点6)

边:节点4 -> 节点6,权值为4 ,minDist[6] > minDist[4] + 4,更新 minDist[6] = minDist[4] + 4 = -2 + 4 = 2 。

将节点6加入队列

如图:


从队列中取出节点5,松弛节点5作为出发点连接的边(节点5 -> 节点3),边(节点5 -> 节点6)

边:节点5 -> 节点3,权值为1 ,minDist[3] > minDist[5] + 1 ,更新 minDist[3] = minDist[5] + 1 = 3 + 1 = 4

边:节点5 -> 节点6,权值为-2 ,minDist[6] > minDist[5] + (-2) ,更新 minDist[6] = minDist[5] + (-2) = 3 - 2 = 1

如图,将节点3加入队列,因为节点6已经在队列里,所以不用重复添加

所以我们在加入队列的过程可以有一个优化,用visited数组记录已经在队列里的元素,已经在队列的元素不用重复加入


从队列中取出节点6,松弛节点6 作为出发点连接的边。

节点6作为终点,没有可以出发的边。

同理从队列中取出节点3,也没有可以出发的边

所以直接从队列中取出,如图:


这样我们就完成了基于队列优化的bellman_ford的算法模拟过程。

大家可以发现 基于队列优化的算法,要比bellman_ford 算法 减少很多无用的松弛情况,特别是对于边数众多的大图 优化效果明显。

了解了大体流程,我们再看代码应该怎么写。

在上面模拟过程中,我们每次都要知道 一个节点作为出发点连接了哪些节点。

如果想方便知道这些数据,就需要使用邻接表来存储这个图,如果对于邻接表不了解的话,可以看 kama0047.参会dijkstra堆 中 图的存储 部分。

思路

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdbool.h>#define MAXN 1000  // 假设最大节点数为1000
#define MAXM 10000 // 假设最大边数为10000typedef struct Edge {int to;   // 链接的节点int val;  // 边的权重struct Edge* next; // 指向下一个边的指针
} Edge;typedef struct {Edge* head; // 邻接表的头
} Vertex;// 创建一个新的边
Edge* createEdge(int to, int val) {Edge* edge = (Edge*)malloc(sizeof(Edge));edge->to = to;edge->val = val;edge->next = NULL;return edge;
}int main() {int n, m, p1, p2, val;scanf("%d %d", &n, &m);Vertex graph[MAXN + 1]; // 邻接表for (int i = 1; i <= n; i++) {graph[i].head = NULL; // 初始化每个节点的头节点}// 将所有边保存起来for (int i = 0; i < m; i++) {scanf("%d %d %d", &p1, &p2, &val);Edge* edge = createEdge(p2, val);edge->next = graph[p1].head; // 插入到邻接表的头部graph[p1].head = edge;}int start = 1; // 起点int end = n;   // 终点int minDist[MAXN + 1];for (int i = 1; i <= n; i++) {minDist[i] = INT_MAX; // 初始化为无穷大}minDist[start] = 0; // 起点到自身的距离为0int queue[MAXN]; // FIFO 队列int front = 0, rear = 0; // 队列的前端和后端bool isInQueue[MAXN + 1] = {false}; // 标记节点是否在队列中queue[rear++] = start; // 将起点加入队列isInQueue[start] = true;while (front < rear) {int node = queue[front++]; // 从队列中取出节点isInQueue[node] = false; // 取消标记for (Edge* edge = graph[node].head; edge != NULL; edge = edge->next) {int to = edge->to; // 获取目的节点int value = edge->val; // 获取边的权重// 松弛操作if (minDist[to] > minDist[node] + value) {minDist[to] = minDist[node] + value;if (!isInQueue[to]) { // 只有不在队列中的节点才加入queue[rear++] = to; // 加入队列isInQueue[to] = true;}}}}// 输出结果if (minDist[end] == INT_MAX) {printf("unconnected\n"); // 不能到达终点} else {printf("%d\n", minDist[end]); // 到达终点最短路径}// 释放分配的内存for (int i = 1; i <= n; i++) {Edge* edge = graph[i].head;while (edge != NULL) {Edge* temp = edge;edge = edge->next;free(temp);}}return 0;
}

学习反思

实现了使用邻接表来存储图,并利用BFS算法求解起点到终点的最短路径。

代码的主要思路如下:

  1. 定义了Edge结构体表示边,Vertex结构体表示节点。
  2. 创建了一个新的边的函数createEdge(),用于分配内存并初始化边的属性。
  3. 读取输入的节点数和边数,并创建邻接表graph。
  4. 使用for循环将所有边保存到邻接表中。
  5. 设置起点和终点,初始化最短路径数组minDist。
  6. 使用FIFO队列和BFS算法求解最短路径。
  7. 输出结果。
  8. 释放动态分配的内存。

这段代码的时间复杂度为O(n+m),其中n为节点数,m为边数。空间复杂度为O(n)。

bellman_ford之判断负权回路

https://www.programmercarl.com/kamacoder/0095.%E5%9F%8E%E5%B8%82%E9%97%B4%E8%B4%A7%E7%89%A9%E8%BF%90%E8%BE%93II.html

本题是 kama94.城市间货物运输I 延伸题目。

本题是要我们判断 负权回路,也就是图中出现环且环上的边总权值为负数。

如果在这样的图中求最短路的话, 就会在这个环里无限循环 (也是负数+负数 只会越来越小),无法求出最短路径。

所以对于 在有负权值的图中求最短路,都需要先看看这个图里有没有负权回路。

接下来我们来看 如何使用 bellman_ford 算法来判断 负权回路。

在 kama94.城市间货物运输I 中 我们讲了 bellman_ford 算法的核心就是一句话:对 所有边 进行 n-1 次松弛。 同时文中的 【拓展】部分, 我们也讲了 松弛n次以上 会怎么样?

在没有负权回路的图中,松弛 n 次以上 ,结果不会有变化。

但本题有 负权回路,如果松弛 n 次,结果就会有变化了,因为 有负权回路 就是可以无限最短路径(一直绕圈,就可以一直得到无限小的最短距离)。

那么每松弛一次,都会更新最短路径,所以结果会一直有变化。

(如果对于 bellman_ford 不了解的录友,建议详细看这里:kama94.城市间货物运输I)

以上为理论分析,接下来我们再画图举例。

我们拿题目中示例来画一个图:

图中 节点1 到 节点4 的最短路径是多少(题目中的最低运输成本) (注意边可以为负数的)

节点1 -> 节点2 -> 节点3 -> 节点4,这样的路径总成本为 -1 + 1 + 1 = 1

而图中有负权回路:

那么我们在负权回路中多绕一圈,我们的最短路径 是不是就更小了 (也就是更低的运输成本)

节点1 -> 节点2 -> 节点3 -> 节点1 -> 节点2 -> 节点3 -> 节点4,这样的路径总成本 (-1) + 1 + (-1) + (-1) + 1 + (-1) + 1 = -1

如果在负权回路多绕两圈,三圈,无穷圈,那么我们的总成本就会无限小, 如果要求最小成本的话,你会发现本题就无解了。

在 bellman_ford 算法中,松弛 n-1 次所有的边 就可以求得 起点到任何节点的最短路径,松弛 n 次以上,minDist数组(记录起到到其他节点的最短距离)中的结果也不会有改变 (如果对 bellman_ford 算法 不了解,也不知道 minDist 是什么,建议详看上篇讲解kama94.城市间货物运输I)

而本题有负权回路的情况下,一直都会有更短的最短路,所以 松弛 第n次,minDist数组 也会发生改变。

那么解决本题的 核心思路,就是在 kama94.城市间货物运输I 的基础上,再多松弛一次,看minDist数组 是否发生变化。

思路

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdbool.h>#define MAXN 1000  // 假设最大节点数
#define MAXM 10000 // 假设最大边数typedef struct {int from; // 边的起点int to;   // 边的终点int weight; // 边的权重
} Edge;int main() {int n, m, p1, p2, val;scanf("%d %d", &n, &m);Edge edges[MAXM]; // 存储所有边for (int i = 0; i < m; i++) {scanf("%d %d %d", &p1, &p2, &val);edges[i].from = p1;edges[i].to = p2;edges[i].weight = val;}int start = 1; // 起点int end = n;   // 终点// 存储从起点到每个节点的最短距离int minDist[MAXN + 1];for (int i = 1; i <= n; i++) {minDist[i] = INT_MAX; // 初始化为无穷大}minDist[start] = 0; // 起点到自身的距离为0bool flag = false; // 标记是否存在负权回路for (int i = 1; i <= n; i++) { // 松弛n次for (int j = 0; j < m; j++) {int from = edges[j].from;int to = edges[j].to;int weight = edges[j].weight;if (i < n) {// 前n-1次,进行正常的松弛if (minDist[from] != INT_MAX && minDist[to] > minDist[from] + weight) {minDist[to] = minDist[from] + weight;}} else {// 第n次,检查是否存在负权回路if (minDist[from] != INT_MAX && minDist[to] > minDist[from] + weight) {flag = true;}}}}// 输出结果if (flag) {printf("circle\n"); // 存在负权回路} else if (minDist[end] == INT_MAX) {printf("unconnected\n"); // 不能到达终点} else {printf("%d\n", minDist[end]); // 到达终点的最短路径}return 0;
}

学习反思

代码是求解带权有向图的单源最短路径问题,使用了Bellman-Ford算法。

算法的思想是从起点开始,进行n-1次松弛操作,每次松弛都尝试通过当前节点更新到达其他节点的最短路径长度。最后,再进行一次松弛操作,如果还能通过该操作更新最短路径,则说明存在负权回路。

具体实现上,通过一个长度为n的数组minDist[]来记录从起点到各个节点的最短路径长度,初始化为INT_MAX,表示无穷大。

在每次松弛操作中,遍历所有边,如果从起点到当前边的起点的路径长度不为无穷大,并且通过该边可以更新到达当前边终点的最短路径长度,则更新minDist[]数组的值。

在最后一次松弛操作中,如果还可以更新最短路径,则说明存在负权回路。

最后根据minDist[end]的值来判断结果,如果为INT_MAX,则说明无法到达终点;如果为负数,则说明存在负权回路;否则,表示到达终点的最短路径长度。

这段代码的时间复杂度为O(nm),其中n为节点数,m为边数。

bellman_ford之单源有限最短路

https://www.programmercarl.com/kamacoder/0096.%E5%9F%8E%E5%B8%82%E9%97%B4%E8%B4%A7%E7%89%A9%E8%BF%90%E8%BE%93III.html

思路

本题为单源有限最短路问题,同样是 kama94.城市间货物运输I 延伸题目。

注意题目中描述是 最多经过 k 个城市的条件下,而不是一定经过k个城市,也可以经过的城市数量比k小,但要最短的路径

在 kama94.城市间货物运输I 中我们讲了:对所有边松弛一次,相当于计算 起点到达 与起点一条边相连的节点 的最短距离

节点数量为n,起点到终点,最多是 n-1 条边相连。 那么对所有边松弛 n-1 次 就一定能得到 起点到达 终点的最短距离。

(如果对以上讲解看不懂,建议详看 kama94.城市间货物运输I )

本题是最多经过 k 个城市, 那么是 k + 1条边相连的节点。 这里可能有录友想不懂为什么是k + 1,来看这个图:

图中,节点1 最多已经经过2个节点 到达节点4,那么中间是有多少条边呢,是 3 条边对吧。

所以本题就是求:起点最多经过k + 1 条边到达终点的最短距离。

对所有边松弛一次,相当于计算 起点到达 与起点一条边相连的节点 的最短距离,那么对所有边松弛 k + 1次,就是求 起点到达 与起点k + 1条边相连的节点的 最短距离。

注意: 本题是 kama94.城市间货物运输I 的拓展题,如果对 bellman_ford 没有深入了解,强烈建议先看 kama94.城市间货物运输I 再做本题。

思路

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>#define MAXN 1000  // 假设最大节点数
#define MAXM 10000 // 假设最大边数typedef struct {int from;     // 边的起点int to;       // 边的终点int weight;   // 边的权重
} Edge;int main() {int src, dst, k, p1, p2, val, m, n;// 读取节点数和边数scanf("%d %d", &n, &m);Edge edges[MAXM]; // 用于存储所有边for (int i = 0; i < m; i++) {scanf("%d %d %d", &p1, &p2, &val);edges[i].from = p1;edges[i].to = p2;edges[i].weight = val;}// 读取源节点、目标节点和最大边数kscanf("%d %d %d", &src, &dst, &k);// 存储从源节点到每个节点的最短距离int minDist[MAXN + 1];for (int i = 1; i <= n; i++) {minDist[i] = INT_MAX; // 初始化为无穷大}minDist[src] = 0; // 源节点到自身的距离为0// 松弛k + 1次for (int i = 1; i <= k + 1; i++) {int tempDist[MAXN + 1]; // 用于存储当前迭代的最短距离for (int j = 1; j <= n; j++) {tempDist[j] = minDist[j]; // 初始化临时数组}// 遍历所有边进行松弛for (int j = 0; j < m; j++) {int from = edges[j].from;int to = edges[j].to;int weight = edges[j].weight;if (tempDist[from] != INT_MAX && tempDist[to] > tempDist[from] + weight) {tempDist[to] = tempDist[from] + weight; // 更新最短路径}}// 将当前迭代的结果更新到minDistfor (int j = 1; j <= n; j++) {minDist[j] = tempDist[j];}}// 输出结果if (minDist[dst] == INT_MAX) {printf("unreachable\n"); // 不能到达目标节点} else {printf("%d\n", minDist[dst]); // 到达目标节点的最短路径}return 0;
}

学习反思

实现了求解单源最短路径问题的算法,采用了Bellman-Ford算法的思想。

首先,通过scanf函数读入节点数n和边数m。

然后,定义了一个结构体Edge用于存储边的信息,包括边的起点、终点和权重。

接下来,使用for循环读入m条边的信息,并将其存储到edges数组中。

再次使用scanf函数读入源节点src、目标节点dst和最大边数k。

然后,定义了一个数组minDist用于存储从源节点到每个节点的最短距离,初始值为无穷大。

接下来,进行k + 1次松弛操作,每次遍历所有边,如果发现存在从from节点到to节点的距离更短的路径,则更新最短距离。

最后,判断到达目标节点的最短路径是否存在,如果不存在则输出"unreachable",否则输出最短路径的值。

该算法的时间复杂度为O(k * m),其中k为最大边数,m为边数。

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

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

相关文章

详解LZ4文件解压缩问题

详解LZ4文件解压缩问题 一、LZ4文件解压缩方法1. 使用LZ4命令行工具2. 使用Python库3. 使用第三方工具4. 在线解压工具 二、常见问题及解决方法1. 解压显示文件损坏2. 解压后文件大小异常 三、总结 LZ4是一种快速的压缩算法&#xff0c;广泛应用于需要实时压缩和解压缩大文件的…

【Linux网络编程】第四弹---构建UDP服务器与字典翻译系统:源码结构与关键组件解析

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【Linux网络编程】 目录 1、UdpServer.hpp 1.1、函数对象声明 1.2、Server类基本结构 1.3、构造函数 1.4、Start() 2、Dict.hpp…

DBA面试题-1

面临失业&#xff0c;整理一下面试题&#xff0c;找下家继续搬砖 主要参考&#xff1a;https://www.csdn.net/?spm1001.2101.3001.4476 略有修改 一、mysql有哪些数据类型 1&#xff0c; 整形 tinyint,smallint,medumint,int,bigint&#xff1b;分别占用1字节、2字节、3字节…

vxe-table 树形表格序号的使用

vxe-table 树形结构支持多种方式的序号&#xff0c;可以及时带层级的序号&#xff0c;也可以是自增的序号。 官网&#xff1a;https://vxetable.cn 带层级序号 <template><div><vxe-grid v-bind"gridOptions"></vxe-grid></div> <…

精通.NET鉴权与授权

授权在.NET 中是指确定经过身份验证的用户是否有权访问特定资源或执行特定操作的过程。这就好比一个公司&#xff0c;身份验证(鉴权)是检查你是不是公司的员工&#xff0c;而授权则是看你这个员工有没有权限进入某个特定的办公室或者使用某台设备。 两个非常容易混淆的单词 鉴…

Spring Task和WebSocket使用

在现代 Web 应用中&#xff0c;WebSocket 作为一种全双工通信协议&#xff0c;为实时数据传输提供了强大的支持。若要确保 WebSocket 在生产环境中的稳定性和性能&#xff0c;使用 Nginx 作为反向代理服务器是一个明智的选择。本篇文章将带你了解如何在 Nginx 中配置 WebSocket…

机器学习任务功略

loss如果大&#xff0c;训练资料没有学好&#xff0c;此时有两个可能&#xff1a; 1.model bias太过简单&#xff08;找不到loss低的function&#xff09;。 解决办法&#xff1a;增加输入的feacture&#xff0c;设一个更大的model&#xff0c;也可以用deep learning增加弹性…

STL:相同Size大小的vector和list哪个占用空间多?

在C中&#xff0c;vector和list是两种不同的序列容器。vector底层是连续的内存&#xff0c;而list是非连续的&#xff0c;分散存储的。因此&#xff0c;vector占用的空间更多&#xff0c;因为它需要为存储的元素分配连续的内存空间。 具体占用多少空间&#xff0c;取决于它们分…

Windows 10电脑无声问题的全面解决方案

Windows 10操作系统以其强大的功能和用户友好的界面赢得了广大用户的青睐&#xff0c;但在使用过程中&#xff0c;有时会遇到电脑突然没有声音的问题。这一问题可能由多种原因引起&#xff0c;包括音频驱动程序问题、音频设置错误、系统更新冲突等。本文将详细介绍Windows 10无…

6.824/6.5840 Lab 1: Lab 3: Raft

漆昼中温柔的不像话 静守着他的遗憾啊 旧的摇椅吱吱呀呀停不下 风卷走了满院的落叶落花 ——暮色回响 完整代码见&#xff1a; https://github.com/SnowLegend-star/6.824 在完成Lab之前&#xff0c;务必把论文多读几遍&#xff0c;力求完全理解Leader选举、log日志等过程。 …

小程序-基于java+SpringBoot+Vue的养老院管理系统设计与实现

项目运行 1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…

YOLOv11 NCNN安卓部署

YOLOv11 NCNN安卓部署 之前自己在验证更换relu激活函数重新训练部署模型的时候&#xff0c;在使用ncnn代码推理验证效果很好&#xff0c;但是部署到安卓上cpu模式会出现大量的错误检测框&#xff0c;现已更换会官方默认的权重 前言 YOLOv11 NCNN安卓部署 目前的帧率可以稳定…

WPF_3

x名称空间的由来和作用 WPF程序中有这样的代码&#xff1a; x:Class"WpfControlLibrary1.UserControl1"<!--这是对x的使用-->xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/…

使用flex布局实现一行固定展示n个元素

前言&#xff1a; 最近在公司中完成小程序的UI设计稿时&#xff0c;遇到了布局一个问题&#xff1a;UI设计稿想实现的布局是这样的&#xff1a; 笔者第一反应就是使用flex中的justify-content: space-between;属性&#xff0c;但是使用之后发现&#xff0c;justify-content: …

Angular v19 (三):增量水合特性详解 - 什么是水合过程?有哪些应用场景?与 Qwik 相比谁更胜一筹?- 哪个技术好我就学哪个,这就是吸心大法吧

Angular在其最新版本 v19 中引入了增量水合&#xff08;Incremental Hydration&#xff09;这一特性。这一更新引发了开发者们广泛的讨论&#xff0c;特别是在优化首屏加载速度和改善用户体验方面。本文将详解水合过程的概念、增量水合的应用场景&#xff0c;以及它与类似框架如…

各类 AI API获取方法,GPT | Claude | Midjourney等

前言 在当今数字化转型的浪潮中&#xff0c;企业和开发者都面临着前所未有的技术挑战与机遇。随着ChatGPT等大语言模型的崛起&#xff0c;AI应用开发已从可选项变成了必选项。在AI应用开发中&#xff0c;成本控制是一个普遍的痛点。单是API调用费用就包含了多个维度&#xff1…

Linux:进程间通信之system V

一、共享内存 进程间通信的本质是让不同的进程看到同一份代码。 1.1 原理 第一步&#xff1a;申请公共内存 为了让不同的进程看到同一份资源&#xff0c;首先我们需要由操作系统为我们提供一个公共的内存块。 第二步&#xff1a;挂接到要通信进程的地址空间中 &#xff…

Python数组拆分(array_split())

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

微信小程序——文档下载功能分享(含代码)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

LabVIEW氢气纯化控制系统

基于LabVIEW的氢气纯化控制系统满足氢气纯化过程中对精确控制的需求&#xff0c;具备参数设置、过程监控、数据记录和报警功能&#xff0c;体现了LabVIEW在复杂工业控制系统中的应用效能。 项目背景 在众多行业中&#xff0c;尤其是石油化工和航天航空领域&#xff0c;氢气作为…