当前位置: 首页 > news >正文

【狂热算法篇】探秘图论之Dijkstra 算法:穿越图的迷宫的最短路径力量(通俗易懂版)

cd9f8d853fd243fd99eba247a02914b5.jpeg              2688ac491550417d940e88f20b721cc9.png 844c1e6ce5a94ed593ab79c4d94f1b2e.png 37def9f4aee046b491f7309ec6975e61.png    10735db0f4594f7d8237fe363f7809c6.png羑悻的小杀马特.-CSDN博客羑悻的小杀马特.擅长C/C++题海汇总,AI学习,c++的不归之路,等方面的知识,羑悻的小杀马特.关注算法,c++,c语言,青少年编程领域.https://blog.csdn.net/2401_82648291?type=bbshttps://blog.csdn.net/2401_82648291?type=bbshttps://blog.csdn.net/2401_82648291?type=bbs

 

在本篇文章中,博主将带大家去学习所谓的Dijkstra算法;从基本理解,画图分析展示,再到最后的代码实现,以及为何要这样实现代码,等一些细节问题做解释,相关题型应用,非常值得哟,尤其是刚入门的小白学习;干货满满,通俗易懂;欢迎大家点赞收藏阅读呀!!!  

d7ed8cb323574a7f8874a1bce287cc4e.png

7a0dc710dea74e729d1a2f5a1fe050dc.gif

 欢迎拜访:羑悻的小杀马特.-CSDN博客

本篇主题:秒懂百科之Dijkstra算法的深度剖析

制作日期:2025.01.27

隶属专栏:美妙的算法世界

目录

一·DIjkstra算法介绍:

1.1算法背景:

1.2形象举例演示:

1.3算法的核心思想和步骤 :

1.3.1初始化:

1.3.2核心步骤:

1.3.3通俗理解:

1.4伪代码模版:

 二·DIjkstra算法朴素版实现:

2.1代码展示:

2.2测试效果:

 2.3时间复杂度分析:

三·DIjkstra算法优化版(优先队列)实现:

3.1优化后代码深度剖析讲解:

3.2代码实现展示: 

3.3测试效果:  

3.4时间复杂度:

四.在线OJ测试:

 五·设计时的细节分析:

5.1为什么我们从dist中选的的最小的点dist值一定是最小源点距?

5.2为什么选择最小源点距的点u去更新v再次放入v对应的dist值不一定是最小的?

5.3为什么每次不是在更新dist操作的时候标记1(对v);而是选出最小源点距的点u后给u标记1?

六·Floyd算法和Dijkstra算法区别:

6.1基本原理:

6.2时间复杂度:

6.3算法实现原理:

6.4使用注意事项:

七·实际应用场景:

7.1网络路由:

7.2交通规划:

7.3地图导航:

7.4资源分配:

八·本篇小结:


 首先我们先大概介绍一下吧:


一·DIjkstra算法介绍:

1.1算法背景:

Dijkstra 算法是由荷兰计算机科学家 Edsger W. Dijkstra 提出的一种用于解决图中单个源点到其他各节点最短路径问题的经典算法。该算法适用于带权有向图或无向图,且图中边的权重必须是非负的。其目的是找到从源节点到图中所有其他节点的最短路径,通过逐步确定最短路径长度的节点集合,不断更新源节点到其他节点的最短距离估计,最终实现找到最短路径的目标。

但是比较形象的我们还是先以例子为引入吧:

我们先明确一下,它可以处理有无向图,但是就是不能处理负权边(后面我们会解释)。

1.2形象举例演示:

8da34c62d7b24e74be1352dd2bde8d2f.png

那么下面我们就按照DIjkstra算法的思路模拟一下这个操作:

三张表:

distflagpre
记录i点到源点的距离(当前认为最小的,后续可能更新)标记已经完成最小源点距的点记录当前点的前驱节点方便找路径
.........

其实还会有个二维path表方便我们 拿到两点及两点边之间的权,其次就是这里我们默认编号从1开始,但是数组下标确实0;我们就从1开始放入。

其实它可以从任意点开始来找到任意点的了路径;那么下面我们就从1号开始:
初始化操作:

f08643937de64f978f73ec7a9a089b60.png

 首选我们先讲一下是如何操作:

每次从dsit数组中选没找到最小dist(flag数组对应位置标记位0);然后它就是最短源点距,给它的flag标记成1;开始从它作为下一个点的前驱,去找到下一个点的距离(如果此时源点可借助这个点到达下一个点比之前距离小就跟新对应dist,然后记录前驱也就是当前这个被选中的点;依次循环知道dist数组对应下标位置都被标记1(即再也找不到,就完成查找工作了))

下面动态效果展示一下:

 不过这里博主有个小错误,不过及时改掉了,大家细心可以看出来:

Dijkstra算法模拟演示

相信到这里大家应该明白了是如何操作的了;那么下面我们着重的就是算法实现了:

1.3算法的核心思想和步骤 :

标准版:

1.3.1初始化

  • 设源节点为 s,将 dist[s] 初始化为 0,将其他节点 v 的 dist[v] 初始化为正无穷大(表示源点到这些节点的最短路径尚未确定)。
  • 维护一个集合 S 表示已确定最短路径的节点集合,初始时 S 为空集。

1.3.2核心步骤

  • 重复以下操作,直到 S 包含所有节点:
  • 从不在 S 中的节点中选取 dist 值最小的节点 u(即当前未确定最短路径节点中距离源点最近的节点),将 u 加入 S。对于 u 的每个邻接节点 v,如果从源节点经过 u 到达 v 的路径比当前已知的 dist[v] 更短,更新 dist[v] 的值。
  • 更新公式为:dist[v] = dist[u] + weight(u, v),其中 weight(u, v) 表示边 (u, v) 的权值。

1.3.3通俗理解:

 这里说白了就是把我们上面模拟的过程翻译成代码:

首先需要两个循环;第一个循环确定已经完成查找到最短源点距的点u,一定要标记好,防止再次查找到它,然后通过u开始拓展找可到达的边,(看看能否借助u到达v的源点距,小于之前dist数组中填写的值,如果小就更换,并且记录前驱节点),依次重复此步骤,直到无法找出中间点即可。

注:那么问题来了,这里难点不是怎么操作,而是怎么判断是否合法,也就是两种选点时候的判断(博主给大家总结好了,以及相关分析):

①选中间点u:

1·这里我们只需要判断,它是否被找到了最短源点距(根据flag数组标记),

2·以及它能不能被源点到达即可(第一次肯定是选的我们标记的0,但是之后如果选出了我们设置的无穷(这个点不能被源点直达,也不可以借助其他中间点到达)也就是它是不能选的,直接就是完成工作了,break掉)

②选中间点u可达的v点:

这里相对就多一点了:

1·首先我们要确保这个v点还没有找到最短路径;

2·其次就是源点可以借助u到达v即u到v有路线(这里我们可以省,因为后面判断两个路线最短时候包含了这点)

3·最重要的就是路线比较了(即借助中间点u的路线和原来填写的路线要最短的进行更新dist数组)

注:这里我们也许会问,这个还要不要判断源点是否可达v;也就是dist[V]不能为无穷?

肯定是不需要,否则第一次以源点作为前驱中间点选择的时候不就完蛋咯。 

掌握这几点,写代码实现就不是问题啦。 

1.4伪代码模版:

下面展示一下伪代码实现的版子:

void Dijkstra(int x) {dist[x] = 0;//标记源点,启动循环while (找中间节点作为前驱) {int u = dist_min();//完成中间点选择不合适直接退出,完成工作 break; //u一定是源点可达的点标记已经找到的最短路的点;//作为中间点一定dist里最短路径,无需更新u了for (遍历剩下节点找可达,进行比较) {if (三大判断条件) {dist[v] = dist[u] + path[u][v];保存前驱}}}
}

 二·DIjkstra算法朴素版实现:

我们实现的朴素版是一种贪心+广度优先搜索。

上面的要点我们都讲完了,代码不成问题了,下面展示下博主自己实现的代码,以及一些细节处理的解释操作(超详细版)

2.1代码展示:

#include<iostream>
#include<vector>
#include<map>
#include<cstring>
using namespace std;
#define IMAX 0x3f3f3f3f
const int N = 6666;
int dist[N];//源点到i的最短距离
bool flag[N] = {0};//为1则i点已找到最短源点距
int path[N][N];//i j之间可达距
int pre[N] ;//前驱节点
int n, m;int dist_min() {//找已完成源最短距的点int id=-1;int M = IMAX;//注意如果dist数组中可选的中间点只有dist为IMAX也就是源点不可达的点;这里必须返回提示一下,也就是找不到id;for (int i = 1; i <= n; i++) {if (!flag[i] && M> dist[i]) {M = dist[i];id = i;}}return id;
}
void Dijkstra(int x) {dist[x] = 0;int tmp = n-1;while (tmp--) {int u = dist_min();if (u == -1) break; //u一定是源点可达的点flag[u] = 1;//作为中间点一定dist里最短路径,无需更新u了for (int v = 1; v <= n; v++) {//符合条件uv可达(间接隐含),v不是最短源点距;符合两路取短if (path[u][v] != IMAX && !flag[v] && dist[v] > dist[u] + path[u][v]) {dist[v] = dist[u] + path[u][v];pre[v] = u;//记录前节点,方便找路径}}}
}
void find_min() {cout << "依次到1~n号节点距离:";for (int i = 1; i <= n; i++) {if (dist[i] == IMAX)cout << -1 << " ";else cout << dist[i] << " ";}
}
void init_pre() {for (int i = 1; i <= n; i++)pre[i] = i;
}
int getpath(int x) {cout << "路径:";pre[x] == x ? x : getpath(pre[x]);cout << x << " ";return x;
}int main() {cin >> n >> m;memset(path, 0x3f, sizeof path);memset(dist, 0x3f, sizeof dist);while (m--) {int u, v, w;cin >> u >> v >> w;path[u][v] = min(path[u][v],w);//path[v][u] = min(path[v][u], w); 无向图}init_pre();Dijkstra(3);find_min();cout << endl;getpath(1);//等于自身可能自身成环也可能无法到达return 0;
}

2.2测试效果:

我们就以上面模拟的为例子;源点选择1号,并查看一下到2号的最短路径:

 d39f55f7825f40cd9a5f92b55436cd00.png 


 2.3时间复杂度分析:

 当然了,这里我们不难发现,时间复杂度由于套了两层循环到了O(N^2)级别;那么可不可以优化呢。但是是可以的;我们可以借助优先队列给它优化一下,这样当数据范围特别大的时候,我们就不用通过手动循环去查找了,而是可以直接利用stl容器特性解决。

三·DIjkstra算法优化版(优先队列)实现:

优化后变成了贪心+优先队列了。

我们已经看到了如果数据大上面的朴素法还是不行的,因此下面就借助优先队列完成:

首先,我们变化的大致可以理解为只是优化了查找中间点u工作以及放入u的临边点v点的操作。

 这里剧透一下:因为我们这操作相当于黑盒,因此我们只管直接拿,直接放(优先队列是混乱的,我们只需要它自己帮我们完成我们想要的操作即可)。

3.1优化后代码深度剖析讲解:

下面就对我们优化实现的代码进行讲解:

①存放已知数据:

vector<pair<int, ll >> v[N];//表示i为始点;v[i]里面的的每个pair的元素代表它的下一个点,以及到达的边权

②存放所有可通过中间点u到达的v点及权值,v前驱中间点:

priority_queue<pair<ll, pair<int, int>>, vector<pair<ll, pair<int, int>>>, greater<>> pq;//编译器根据对象自动推导模版类型
//其次就是注意外层pair顺序:我们是优先以路径长短作为判断的ll和int不能颠倒(与定义的vector的pair类型不同)

③剖析解释一下这个优先队列:

 这里的优队就是为了把遍历朴素法的dist数组的复杂直接转成靠stl容器完成选择出这个已经找到最短路径的中间点(然后开始搜索继续放入队列)。
这里为了我们不仅可以知道源点到某点的最短距离以及路径;故我们每次都把前驱节点推进去: 点 源点到此点的距离 此条路上某点的前驱节点

注:队列中的元素不完全是某点最短路径长度,是所有能到达此点的路径(依靠stlpq的性质完成自己筛选出最短) 

④这两个容器变量类型不能混杂:

注意外层pair顺序:我们是优先以路径长短作为判断的ll和int不能颠倒(与定义的vector的pair类型不同)

那么下面我们来阐述一下优先队列是如何操作的:

1·选择中间点u:首先我们把源点推进去,启动优先队列的操作;接着就是确认源点已经是最短源点距;给它标记(防止下一次还选到它);注:符合中间点筛选条件;选择后一定要pop掉(防止队列死循环发生),其次,就是如果选择的中间点已经找到了最短路径,我们就要跳过它然后重新从优先队列中选择。

2·选择可达边对应的点v:

这里我们无需判断在选了(因为说过优先队列里面是混乱的,我们无需考虑,但是最后拿到的经判断后一定是我们想要的);全部无论距离是多少直接把相应的源点距和对应的点搞进去;这里相当于把我们朴素版的判断优化到了极致。

3.2代码实现展示: 

#include<iostream>
#include<queue>
#include<vector>
#include<map>
#include<functional>
#include<cstring>
using namespace std;
using ll = long long;
const int N = 3e5 + 5;
constexpr ll  IMAX = 1e15;
vector<pair<int, ll >> v[N];//表示i为始点;v[i]里面的的每个pair的元素代表它的下一个点,以及到达的边权
//这里的优队就是为了把遍历朴素法的dist数组的复杂直接转成靠stl容器完成选择出这个已经找到最短路径的中间点(然后开始搜索继续放入队列)
//注:队列中的元素不完全是某点最短路径长度,是所有能到达此点的路径(依靠stlpq的性质完成自己筛选出最短)
//这里为了我们不仅可以知道源点到某点的最短距离以及路径;故我们每次都把前驱节点推进去: 点 源点到此点的距离 此条路上某点的前驱节点
priority_queue<pair<ll, pair<int, int>>, vector<pair<ll, pair<int, int>>>, greater<>> pq;//编译器根据对象自动推导模版类型
//其次就是注意外层pair顺序:我们是优先以路径长短作为判断的ll和int不能颠倒(与定义的vector的pair类型不同)
bool check[N];//防止对已经找到最小路径的边重复判断
int n, m;
ll dist[N];//源点到某点的最短路径表
int pre[N];//某点的在源点到达它最短路径上的前驱结点,一直递归下去可以到达源点
void init() {memset(check, 0, 4 * (n + 1));for (int i = 1; i <= n; i++)pre[i] = i;for (int i = 1; i <= n; i++)dist[i] = IMAX;
}
void Dijkstra(int x) {pq.emplace(0LL,make_pair(x,x));//把第一个推进去启动查找while (!pq.empty()) {auto [sourd, p] = pq.top();pq.pop();//防止死循环if (check[p.first])continue;//其实就是朴素版的(check判断)://已经确定了某点最短路径;如果再次找到其前驱节点与它之间有连接,那么这条路一定不是//比它短的,而且已经找到了最小路径,所以不能再更新dist了。pre[p.first] = p.second;//保存其最短路径终点的前驱节点dist[p.first] = sourd;//填充dist表check[p.first] = 1;//获得最短路径了,下次这个就不能再作为中间点了for (auto [next, dis] : v[p.first]) {pq.emplace(dis+dist[p.first], make_pair(next, p.first));//都推进去,依靠pq特性选择最短(pq里是“很乱的”)}}
}
int getpath(int x) {pre[x] == x ? x : getpath(pre[x]);cout << x << " ";return x;
}
void getdis() {for (int i = 1; i <= n; i++) {if (dist[i] == IMAX) cout << -1 << ' ';else cout << dist[i] << ' ';}
}
int main() {cin >> n >> m;init();while (m--) {int x, y, z;cin >> x >> y >> z;v[x].emplace_back(make_pair(y, z));//v[y].emplace_back(make_pair(x, z));//双向边处理}Dijkstra(1);getdis();cout << endl;getpath(2);//等于自身可能自身成环也可能无法到达
}

3.3测试效果:  

效果是同样的。

6ed1e1ff90ea48789f2016d567c7d1d6.png

3.4时间复杂度:

设边数为E,点数为V:

对节点的操作:需要对每个节点进行操作,包括初始化、从优先队列中取出节点,这部分的时间复杂度是 O(VlogV)。

对边的操作:对每条边进行松弛操作并更新距离,时间复杂度为 O(ElogV)。

即使用优先队列优化后的 Dijkstra 算法的时间复杂度为 O((V+E)logV)。

四.在线OJ测试:

 首先我们以一道题来测试下我们写的代码;当然了一般拿Dijkstra算法出题肯定朴素版大概过不了,只能优先化后出场了:

 2bdf6b7e67de4311952ccecd1c760246.png 

OJ链接:蓝桥账户中心 

测试用例:

 76475d10c68a498f88c88d795e1b7e93.png  

此题注意好数据范围:

  080c5ec34f9c4aec999b7bfae47d13a0.png 

这里如果每个点之间都是10^9那么就超越整型范围了,因此我们最好用long long。 

代码展示(优先队列版):

#include<iostream>
#include<queue>
#include<vector>
#include<map>
#include<functional>
#include<cstring>
using namespace std;
using ll = long long;
const int N = 3e5 + 5;
#define IMAX 1e15
vector<pair<int, ll >> v[N];
priority_queue<pair<ll, pair<int, int>>, vector<pair<ll, pair<int, int>>>, greater<pair<ll, pair<int, int>>>> pq;
bool check[N];
int n, m;
ll dist[N];
int pre[N];
void Dijkstra(int x) {pq.emplace(0LL,make_pair(x,x));while (!pq.empty()) {auto [sourd, p] = pq.top();pq.pop();if (check[p.first])continue;pre[p.first] = p.second;dist[p.first] = sourd;check[p.first] = 1;for (auto [next, dis] : v[p.first]) {pq.emplace(dis+dist[p.first], make_pair(next, p.first));}}
}
int main() {cin >> n >> m;memset(check, 0, 4 * (n + 1));for (int i = 1; i <= n; i++)pre[i] = i;for (int i = 1; i <= n; i++)dist[i] = IMAX;while (m--) {int x, y, z;cin >> x >> y >> z;v[x].emplace_back(make_pair(y, z));}Dijkstra(1);for (int i = 1; i <= n; i++) {if (dist[i] == IMAX) cout << -1 << ' ';else cout << dist[i] << ' ';}
}

最后也是通过:

 3c420a9cdee54e418b15412dba941189.png  

 五·设计时的细节分析:

相信大家肯定有类似这样的疑惑,那么下面就来一一举例为大家解答疑惑:

5.1为什么我们从dist中选的的最小的点dist值一定是最小源点距?

相信大家一开始也肯定有题目叙述这样的疑惑:

其实很简单,我们反证法证明一下:

2c25e5b6fe694f4e99f9ea4e769d484c.png

这里我们假设我们所选的C这个点dist里面虽然是最小的,但是不是它的到A点的最短源点距。 

那么肯定存在一条路A~C其中经历了B作为C的前驱结点是最短了(如果存在的话B肯定没有被选到,否则就与上面路重复了,是一条了),明显肯定A到B一定要是比选的C的dist值小;但是这样我们就不会选到C了而是B;与我们假设矛盾,故不成立;即选择其中dist值最小的点一定是最小源距已完成的点,不会再更新。

5.2为什么选择最小源点距的点u去更新v再次放入v对应的dist值不一定是最小的?

还是先看图,在分析:

aaf322d66b4e4e9ea874249462116b47.png

首先我们先选的中间点肯定是C(c和E之间);然后更新D的dist值为11(比100大);之后中间点又会去选C;此时还会去更新D的dist值;故解答标题所述疑惑。 

5.3为什么每次不是在更新dist操作的时候标记1(对v);而是选出最小源点距的点u后给u标记1?

首先我们要明白如果我们标记了某个点,之后还有通往这个点的路径的时候(可能是更短);那么我们就无法更新了;还是看图:

28f628b124ba4be6b71cc85249890f52.png

这里比如选中间点我们从D和B之间选了B;那么直接找到v即C 距离10小于12故更新;如果此时标记C;那么当我们下一次选D会发现路径是7比之前还小;但是已经标记了无法修改故会出错。 

六·Floyd算法和Dijkstra算法区别:

博主也写了篇Floyd算法的文章,大家不懂可以去看,也是通俗易懂的哦;

传送门:【狂热算法篇】探秘图论之 Floyd 算法:解锁最短路径的神秘密码(通俗易懂版)-CSDN博客

首先我们明白区别,下面分为几个点来介绍:

6.1基本原理:

首先Floyd算法是遍历每个点作为终止点的前驱节点进行填表,它进行一次就可以得到每个点到每个店之间的最小路径;即是多源路径。

而Dijkstra算法:它是以一个确定的源点固定好去依次找最短路径来确定源点到某点的距离;认为只要是最短的那么通过它到到达源点一定是最短的(是一种贪心思想,忽略了边权位负数情况,后面会分析);即单源路径。

6.2时间复杂度:

时间复杂度对于Floyd算法三层循环直接拉到了o(N^3);而dijkstra算法朴素是o(N^2);优先队列优化后是o(logN)。

6.3算法实现原理:

Floyd算法基于广搜+动态规划实现;而Dijkstra算法基于贪心+广搜或优先队列实现。

6.4使用注意事项:

首先先表明观点:

先介绍下什么是父负环:即一条回路边权之和为负数;如图:

bca2877490c646fe855110d29d1fa562.png

这样我们会发现是找不到某两点之间的最小路径的,因为这个环可以无限循环。

Dijkstra算法不能应用于负边权(更不要提负环了)(为什么呢?)

首先我们要明白它是种贪心的思路(当找到我们目前认为的最小值,它就会确定下来某点的最短源点距,进而不再更新):

54024f0eb66f4f92a1351fa9548adf04.png

比如我们通过A作为源点,选择了B D更新dist发现最小的B那么我们就会通过这种贪心思想确定B最短源点距就是2;当通过D就不会再去更新B(但是此时源点距为-4小于2);这就违背了事实。

 Floyd算法能用于负边但不能应用于负环:

这里是因为我们会每次把每个店作为终点的前驱中间点遍历一遍然后更新一下目前的最短距离表,那么到最后每个点都遍历完的时候肯定会找到最短路径(此时会考虑到负边权情况);但是对于负环:上面也介绍了无法找出;但是可以通过Bellman_Ford算法检测出来,这里就不多说了。

七·实际应用场景:


7.1网络路由:

在计算机网络中,用于计算从源路由器到其他路由器的最短路径,以优化数据包的传输路径,减少网络延迟和提高网络性能。

7.2交通规划:

计算城市间的最短行车路线,帮助规划最优的交通路径,减少交通拥堵和行程时间

7.3地图导航

计算城市间的最短行车路线,帮助规划最优的交通路径,减少交通拥堵和行程时间。

7.4资源分配

在资源分配问题中,如电力网络中从发电站到各个用户的最短传输路径计算,优化电力传输,减少能源损耗。

八·本篇小结:

四种最短路径算法小总结:

下面基于博主自主学习了了Dijkstra算法的个人理解,希望有帮助: 

首先我们可以如果实在理解不了就可以看一遍博主模拟的过程背一背模版(上面);其实也不难理解;就是标记好源点,然后选中间点(第一次就是源点)然后依次找可达点根据限定条件更新dist数组就完了(朴素版)对于优化版--->只不过是把我们判断条件交给优先队列自己实现了(大量条件)(个人还是觉得优化版更加舒服代码还少啊哈哈哈);总之图论学习尚未结束;后序博主还会进行更新的欢迎大家订阅。

ac1a7fa8134c43beb15a37f0f0b3c26b.png

相关文章:

【狂热算法篇】探秘图论之Dijkstra 算法:穿越图的迷宫的最短路径力量(通俗易懂版)

羑悻的小杀马特.-CSDN博客羑悻的小杀马特.擅长C/C题海汇总,AI学习,c的不归之路,等方面的知识,羑悻的小杀马特.关注算法,c,c语言,青少年编程领域.https://blog.csdn.net/2401_82648291?typebbshttps://blog.csdn.net/2401_82648291?typebbshttps://blog.csdn.net/2401_8264829…...

Electricity Market Optimization 探索系列(一)

​ 本文参考链接&#xff1a;Linear Programming Mini Example 先从一个线性规划的例子说起&#xff1a; 问题背景&#xff1a; 现在需要使用两台发电机满足用户的用电需求&#xff0c;发电机一的发电功率上限是 6MW&#xff0c;发电机二的发电功率上限是 4MW&#xff0c;发电…...

<iframe>标签和定时调用函数setInterval

iframe 标签和定时调用函数 setInterval 问题描述&#xff1a;解决方法&#xff1a; 问题描述&#xff1a; 今天遇到一个前端问题&#xff0c;在浏览器页面上传Excel文件后&#xff0c;然后点击导入按钮&#xff0c;经后端Java类读取文件内容校验后&#xff0c;将校验结果返回…...

网工_HDLC协议

2025.01.25&#xff1a;网工老姜学习笔记 第9节 HDLC协议 9.1 HDLC高级数据链路控制9.2 HDLC帧格式&#xff08;*控制字段&#xff09;9.2.1 信息帧&#xff08;承载用户数据&#xff0c;0开头&#xff09;9.2.2 监督帧&#xff08;帮助信息可靠传输&#xff0c;10开头&#xf…...

Elasticsearch:如何搜索含有复合词的语言

作者&#xff1a;来自 Elastic Peter Straer 复合词在文本分析和标记过程中给搜索引擎带来挑战&#xff0c;因为它们会掩盖词语成分之间的有意义的联系。连字分解器标记过滤器等工具可以通过解构复合词来帮助解决这些问题。 德语以其长复合词而闻名&#xff1a;Rindfleischetik…...

【Go语言圣经】第六节:方法

第六章&#xff1a;方法 6.1 方法声明 在函数声明时&#xff0c;在其名字之前放上一个变量&#xff0c;这就是声明了变量对应类型的一个方法&#xff0c;相当于为这种类型定义了一个独占的方法。 下例为 Point 类型声明了计算两个点之间距离的方法&#xff1a; package mai…...

[答疑]DDD伪创新哪有资格和仿制药比

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 远航 2025-1-24 10:40 最近的热门话题仿制药&#xff0c;想到您经常批评的伪创新&#xff0c;这两者是不是很像&#xff1f; UMLChina潘加宇 伪创新哪有资格和仿制药比。 仿制药的…...

MySQL(高级特性篇) 13 章——事务基础知识

一、数据库事务概述 事务是数据库区别于文件系统的重要特性之一 &#xff08;1&#xff09;存储引擎支持情况 SHOW ENGINES命令来查看当前MySQL支持的存储引擎都有哪些&#xff0c;以及这些存储引擎是否支持事务能看出在MySQL中&#xff0c;只有InnoDB是支持事务的 &#x…...

javascript常用函数大全

javascript函数一共可分为五类&#xff1a; •常规函数 •数组函数 •日期函数 •数学函数 •字符串函数 1.常规函数 javascript常规函数包括以下9个函数&#xff1a; (1)alert函数&#xff1a;显示一个警告对话框&#xff0c;包括一个OK按钮。 (2)confirm函数&#xff1a;显…...

第26节课:内容安全策略(CSP)—构建安全网页的防御盾

目录 CSP基础CSP的作用CSP的主要属性 配置CSP通过响应头配置CSP通过HTML <meta>标签配置CSP属性设置详解指定多个来源 配置示例说明 常见错误配置实践&#xff1a;CSP与XSS防护示例1&#xff1a;防止内联脚本和样式说明示例2&#xff1a;限制图片来源说明 限制与注意事项…...

【大坑】使用element-ui弹窗$confirm自动弹出

插入element-ui的弹窗后页面一刷新自动弹出&#xff0c;事件绑定、调用位置&#xff08;生命周期&#xff09;均没有问题&#xff0c;通过不断注释组件发现是main.js全局引入导致的问题。如果需要在某些组件中使用三方弹窗&#xff0c;可以按需引入&#xff0c;而不是全局注册 …...

Spring的AOP思想中事物管理注意点

我们以事务管理实现AOP思想 通过在Service层加入事务管理,因为Service层可能使用多个DAO(多条SQL语句) 要保证这些SQL要么同时成功,要么同时失败,例如:学生Serivce:删除学生的时候,还需要删除学生关联信息(选课信息) 只有都删除成功才提交,如果有一条执行失败…...

PHP Mail:高效邮件发送解决方案详解

PHP Mail&#xff1a;高效邮件发送解决方案详解 引言 在互联网时代&#xff0c;邮件作为最常用的沟通方式之一&#xff0c;已经成为企业和个人不可或缺的通讯工具。PHP作为一种流行的服务器端脚本语言&#xff0c;在邮件发送方面具有天然的优势。本文将详细介绍PHP Mail&…...

python recv的概念和使用案例

recv 是网络编程中用于从套接字接收数据的核心函数&#xff0c;常见于 TCP/UDP 通信。以下是其概念、用法和案例详解&#xff1a; 概念 作用&#xff1a;从已连接&#xff08;TCP&#xff09;或已绑定&#xff08;UDP&#xff09;的套接字接收数据。参数&#xff1a; bufsize:…...

安卓(android)读取手机通讯录【Android移动开发基础案例教程(第2版)黑马程序员】

一、实验目的&#xff08;如果代码有错漏&#xff0c;可在代码地址查看&#xff09; 1.熟悉内容提供者(Content Provider)的概念和作用。 2.掌握内容提供者的创建和使用方法。 4.掌握内容URI的结构和用途。 二、实验条件 1.熟悉内容提供者的工作原理。 2.掌握内容提供者访问其…...

Java知识速记 == 与equals

Java知识速记 与equals 1. 操作符概述 操作符用于比较基本数据类型的值&#xff0c;或者比较引用类型的对象是否指向同一内存地址。对于基本数据类型&#xff0c;例如int、float等&#xff0c;会比较其值&#xff1b;但对于对象&#xff0c;只会比较两个对象的引用&#xff…...

web集群

项目名称 基于keepalivednginx构建一个高可用、高性能的web集群 项目架构图 项目描述 基本描述 构建一个基于 Nginx 的 7 层负载均衡的 Web 集群系统&#xff0c;模拟企业级业务环境&#xff0c;实现高并发和高可用性的 Web 集群。通过压力测试验证集群性能&#xff0c;找…...

HTMLCSS :下雪了

这段代码创建了一个动态的雪花飘落加载动画&#xff0c;通过 CSS 技术实现了雪花的下落和消失效果&#xff0c;为页面添加了视觉吸引力和动态感。 大家复制代码时&#xff0c;可能会因格式转换出现错乱&#xff0c;导致样式失效。建议先少量复制代码进行测试&#xff0c;若未能…...

Kafka SSL(TLS)安全协议

文章目录 Kafka SSL&#xff08;TLS&#xff09;安全协议1. Kafka SSL 的作用1.1 数据加密1.2 身份认证1.3 数据完整性1.4 防止中间人攻击1.5 确保安全的分布式环境1.6 防止拒绝服务&#xff08;DoS&#xff09;攻击 2. Kafka SSL 配置步骤&#xff08;1&#xff09;创建 SSL 证…...

WebForms SortedList 深度解析

WebForms SortedList 深度解析 引言 在Web开发领域,对于数据结构的理解与应用至关重要。其中,SortedList类在WebForms中是一个常用的数据结构,它能够帮助开发者高效地管理有序数据集合。本文将深入解析SortedList类在WebForms中的应用,包括其基本概念、常用方法、性能特点…...

项目集成Spring Security认证部分

一、需求分析 在本项目中&#xff0c;使用了Spring Security框架来进行认证和授权管理。由于是前后端分离的项目&#xff0c;所有认证的请求需要通过Token来验证身份&#xff0c;系统中包括了用户登录、角色授权以及资源访问控制等功能。 系统中的资源控制&#xff1a; 白名单…...

【PyTorch】7.自动微分模块:开启神经网络 “进化之门” 的魔法钥匙

目录 1. 梯度基本计算 2. 控制梯度计算 3. 梯度计算注意 4. 小节 个人主页&#xff1a;Icomi 专栏地址&#xff1a;PyTorch入门 在深度学习蓬勃发展的当下&#xff0c;PyTorch 是不可或缺的工具。它作为强大的深度学习框架&#xff0c;为构建和训练神经网络提供了高效且灵活…...

【算法】回溯算法专题① ——子集型回溯 python

目录 引入变形实战演练总结 引入 子集 https://leetcode.cn/problems/subsets/description/ 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 …...

Nginx 安装配置指南

Nginx 安装配置指南 引言 Nginx 是一款高性能的 HTTP 和反向代理服务器&#xff0c;同时也可以作为 IMAP/POP3/SMTP 代理服务器。由于其稳定性、丰富的功能集以及低资源消耗而被广泛应用于各种场景。本文将为您详细介绍 Nginx 的安装与配置过程。 系统要求 在安装 Nginx 之…...

深度学习 DAY3:NLP发展史

NLP发展史 NLP发展脉络简要梳理如下&#xff1a; (远古模型&#xff0c;上图没有但也可以算NLP&#xff09; 1940 - BOW&#xff08;无序统计模型&#xff09; 1950 - n-gram&#xff08;基于词序的模型&#xff09; (近代模型&#xff09; 2001 - Neural language models&am…...

Spring Data JPA 实战:构建高性能数据访问层

1 简介 1.1 Spring Data JPA 概述 1.1.1 什么是 Spring Data JPA? Spring Data JPA 是 Spring Data 项目的一部分,旨在简化对基于 JPA 的数据库访问操作。它通过提供一致的编程模型和接口,使得开发者可以更轻松地与关系型数据库进行交互,同时减少了样板代码的编写。Spri…...

全程Kali linux---CTFshow misc入门(25-37)

第二十五题&#xff1a; 提示&#xff1a;flag在图片下面。 直接检查CRC&#xff0c;检测到错误&#xff0c;就直接暴力破解。 暴力破解CRC的python代码。 import binascii import struct def brute_force_ihdr_crc(filename): # 读取文件二进制数据 with open(filen…...

【Elasticsearch】match_bool_prefix 查询 vs match_phrase_prefix 查询

Match Bool Prefix Query vs. Match Phrase Prefix Query 在 Elasticsearch 中&#xff0c;match_bool_prefix 查询和 match_phrase_prefix 查询虽然都支持前缀匹配&#xff0c;但它们的行为和用途有所不同。以下是它们之间的主要区别&#xff1a; 1. match_bool_prefix 查询…...

被裁与人生的意义--春节随想

还有两个月就要被迫离开工作了十多年的公司了&#xff0c;不过有幸安安稳稳的过了一个春节&#xff0c;很知足! 我是最后一批要离开的&#xff0c;一百多号同事都没“活到”蛇年。看着一批批仁人志士被“秋后斩首”&#xff0c;马上轮到我们十来个&#xff0c;个中滋味很难言清…...

DNS缓存详解(DNS Cache Detailed Explanation)

DNS缓存详解 清空DNS缓存可以让网页访问更快捷。本文将从什么是DNS缓存、为什么清空DNS缓存、如何清空DNS缓存、清空DNS缓存存在的问题四个方面详细阐述DNS缓存清空的相关知识。 一、什么是DNS缓存 1、DNS缓存的定义&#xff1a; DNS缓存是域名系统服务在遇到DNS查询时自动…...

深度学习之“线性代数”

线性代数在深度学习中是解决多维数学对象计算问题的核心工具。这些数学对象包括标量、向量、矩阵和张量&#xff0c;借助它们可以高效地对数据进行操作和建模。以下将详细介绍这些数学对象及其在深度学习中的典型用途。 数学对象概述 标量 标量是最简单的数学对象&#xff0…...

【论文阅读】RAG-Reward: Optimizing RAG with Reward Modeling and RLHF

研究背景 研究问题&#xff1a;这篇文章要解决的问题是如何优化检索增强生成&#xff08;RAG&#xff09;系统&#xff0c;特别是通过奖励建模和人类反馈强化学习&#xff08;RLHF&#xff09;来提高大型语言模型&#xff08;LLMs&#xff09;在RAG任务中的效果。研究难点&…...

新一代搜索引擎,是 ES 的15倍?

Manticore Search介绍 Manticore Search 是一个使用 C 开发的高性能搜索引擎&#xff0c;创建于 2017 年&#xff0c;其前身是 Sphinx Search 。Manticore Search 充分利用了 Sphinx&#xff0c;显着改进了它的功能&#xff0c;修复了数百个错误&#xff0c;几乎完全重写了代码…...

鸿蒙物流项目之实现广告页

目录&#xff1a; 1、广告页布局2、倒计时的实现 1、广告页布局 鸿蒙官方有提供实现广告页的方法&#xff0c;这里我们不使用&#xff0c;使用自定义广告页。 2、倒计时的实现 在页面加载时实现倒计时功能&#xff0c;在页面倒计时为0时跳转其他页面后销毁页面后同时也要销毁定…...

自制虚拟机(C/C++)(二、分析引导扇区,虚拟机读二进制文件img软盘)

先修复上一次的bug&#xff0c;添加新指令&#xff0c;并增加图形界面 #include <graphics.h> #include <conio.h> #include <windows.h> #include <commdlg.h> #include <iostream> #include <fstream> #include <sstream> #inclu…...

S4 HANA给科目分配允许记账的税码

本文主要介绍在S4 HANA OP中给科目分配允许记账的税码相关设置。具体请参照如下内容&#xff1a; 1. 给科目分配允许记账的税码 以上配置定义了总账科目可以使用什么税码进行记账。通常在科目主数据中会明确总账科目的“Tax Category”来请明确总账科目可以使用什么类型的税码…...

【LeetCode 刷题】回溯算法-组合问题

此博客为《代码随想录》二叉树章节的学习笔记&#xff0c;主要内容为回溯算法组合问题相关的题目解析。 文章目录 77. 组合216.组合总和III17.电话号码的字母组合39. 组合总和40. 组合总和 II 77. 组合 题目链接 class Solution:def combinationSum3(self, k: int, n: int) …...

Automatic Prefix Caching

APC技术&#xff0c;遇到新prompt和老prompt前缀完全相等的&#xff0c;则复用老prompt的KV cache&#xff0c;避免重新计算。 VLLM代码实例&#xff1a; # set enable_prefix_cachingTrue to enable APC llm LLM(modellmsys/longchat-13b-16k,enable_prefix_cachingTrue ) 应…...

DDD - 领域事件_解耦微服务的关键

文章目录 Pre领域事件的核心概念领域事件的作用领域事件的识别领域事件的技术实现领域事件的运行机制案例领域事件驱动的优势 Pre DDD - 微服务设计与领域驱动设计实战(中)_ 解决微服务拆分难题 EDA - Spring Boot构建基于事件驱动的消息系统 领域事件的核心概念 领域事件&a…...

吴晓波 历代经济变革得失@简明“中国经济史” - 读书笔记

目录 《历代经济变革得失》读书笔记一、核心观点二、主要内容&#xff08;一&#xff09;导论&#xff08;二&#xff09;春秋战国时期&#xff08;三&#xff09;汉代&#xff08;四&#xff09;北宋&#xff08;五&#xff09;明清时期&#xff08;六&#xff09;近现代&…...

Ubuntu下的Doxygen+VScode实现C/C++接口文档自动生成

Ubuntu下的DoxygenVScode实现C/C接口文档自动生成 Chapter1 Ubuntu下的DoxygenVScode实现C/C接口文档自动生成1、 Doxygen简介1. 安装Doxygen1&#xff09;方法一&#xff1a;2&#xff09;方法二&#xff1a;2. doxygen注释自动生成插件3. doxygen注释基本语法4. doxygen的生成…...

论文阅读:Realistic Noise Synthesis with Diffusion Models

这篇文章是 2025 AAAI 的一篇工作&#xff0c;主要介绍的是用扩散模型实现对真实噪声的仿真模拟 Abstract 深度去噪模型需要大量来自现实世界的训练数据&#xff0c;而获取这些数据颇具挑战性。当前的噪声合成技术难以准确模拟复杂的噪声分布。我们提出一种新颖的逼真噪声合成…...

【Linux系统】计算机世界的基石:冯诺依曼架构与操作系统设计

文章目录 一.冯诺依曼体系结构1.1 为什么体系结构中要存在内存&#xff1f;1.2 冯诺依曼瓶颈 二.操作系统2.1 设计目的2.2 系统调用与库函数 一.冯诺依曼体系结构 冯诺依曼体系结构&#xff08;Von Neumann Architecture&#xff09;是计算机的基本设计理念之一&#xff0c;由…...

p1044 栈

两种递推细节不同 1,将1和n在序列末尾的情况单独放出来处理&#xff0c;因为dp[0]0&#xff1b; 2,将所有情况统一处理&#xff0c;这种情况就要要求dp[1]1; 这里的n在解题中可以看做是元素数量 思路是&#xff0c;根据出栈最后一个元素,统计它前面的元素数量的输出序列数和…...

x86-64数据传输指令

关于汇编语言一些基础概念的更详细的介绍&#xff0c;可移步MIPS指令集&#xff08;一&#xff09;基本操作_mips指令 sw-CSDN博客 该指令集中一个字2字节。 该架构有16个64位寄存器&#xff0c;名字都以%r开头&#xff0c;每个寄存器的最低位字节&#xff0c;低1~2位字节&…...

C++11新特性之lambda表达式

1.介绍 C11引入了lambda表达式。lambda表达式提供一种简洁的方式来定义匿名函数对象&#xff0c;使得在需要临时定义一个函数时非常方便。 2.lambda表达式用法 lambda表达式的基本用法为&#xff1a; [捕获列表]&#xff08;参数列表&#xff09;->返回类型 { 函数体 …...

51单片机密码锁代码

基于液晶屏外设写的. main.c #include <REGX52.H> #include "LCD1602.h" #include "MatrixKey.h" #include "Sleep.h" long password1234; long resNum0; int status0,res0,k1500; long birth2005; void main(){LCD_Init();LCD_ShowStr…...

如何使用C#的using语句释放资源?什么是IDisposable接口?与垃圾回收有什么关系?

在 C# 中,using语句用于自动释放实现了IDisposable接口的对象所占用的非托管资源,如文件句柄、数据库连接、图形句柄等。其使用方式如下: 基础用法 声明并初始化资源对象:在using关键字后的括号内声明并初始化一个实现了IDisposable接口的对象。使用资源:在using语句块内…...

【Unity3D】实现横版2D游戏——单向平台(简易版)

目录 问题 项目Demo直接使用免费资源&#xff1a;Hero Knight - Pixel Art &#xff08;Asset Store搜索&#xff09; 打开Demo场景&#xff0c;进行如下修改&#xff0c;注意Tag是自定义标签SingleDirCollider using System.Collections; using System.Collections.Generic;…...

BW AO/工作簿权限配置

场景&#xff1a; 按事业部配置工作簿权限&#xff1b; 1、创建用户 事务码&#xff1a;SU01&#xff0c;用户主数据的维护&#xff0c;可以创建、修改、删除、锁定、解锁、修改密码等 用户设置详情页 2、创建权限角色 用户的权限菜单是通过权限角色分配来实现的 2.1、自定…...