弗洛伊德算法-寻找最短路径(无权/有权图)

前言:弗洛伊德算法-寻找最短路径学习和实现笔记

什么是弗洛伊德算法-寻找最短路径

个人理解,正常的一个图,将其转化为一个邻接矩阵,在邻接矩阵中,每一个权值实际上就是一个顶点到另外一个顶点之间的距离。

那这里我举个例子,比如如下的情况

首先需要知道下什么是中转顶点(我自己是这样叫的,野路子),比如图中的一个顶点1到一个顶点3之间可以通过中转顶点2到达,这种节点就称之为中转节点

  • 第一次的时候,当加入了一个中转顶点1,之后那么接下来的顶点1,2,3,4,5都可以通过中转顶点1来达到原本直连是连接不到的顶点,又或者可以通过更少的权值来达到原本权值比较大的顶点

  • 这里加入顶点1之后,那么我们这里从顶点1开始,但是你会发现从顶点1开始没有必要

原因是加入了中转顶点1,对于顶点1本身没有任何影响

  • 那么我们这里就从顶点2开始,当对于顶点2来说,顶点1中转节点,那么顶点2到顶点1的距离还是10,但是顶点2到顶点5之间就可以通过顶点1来实现到达,那么在邻接矩阵中对于顶点2到顶点5来说之间的权值原本是无穷,但是这里是有向图,所以还是无法到达

  • 接着顶点2到顶点3(通过顶点5无法到达),所以权值还是原来的50,那么顶点2到顶点4无法到达,因为这个是有向图

  • 就这样以此类推即可完全各个顶点之间的最短路径

关于对最短路径的寻找

当你把各个顶点之间的最短路径求出来之后,那么要怎么寻找一个顶点到一个顶点之间的最短路径呢?首先要明白的就是最短路径是针对于顶点的

就比如说下面这张图,我要先找到一条顶点1到顶点5之间的最短路径

  • 那么首先我先从第1行的第5列,我发现这个点是顶点4(下标0开始)

  • 那么我就继续从第1行的第4列找,我发现它指向的是-1,那么这里是-1就说明顶点1到顶点4之间是没有中间路径的,那么此时的路径就是 顶点1 -> 顶点4

  • 但是顶点4和顶点5之间不一定没有路径,所以这里还需要从第4行的第5列中找,因为不一定顶点4能够直接到达顶点5,可能有更小的权值的顶点在其中,发现这里指向的是顶点3(下标0开始)

  • 所以这里又要继续在第4行的第3列中找,发现是-1

  • 这里还需要看下第3行的第5列,发现也是-1

  • 那到这里的话就结束了

  • 顶点1到顶点4之间的最短路径就是 顶点1 -> 顶点4 -> 顶点3 -> 顶点5

那么如何通过代码实现寻找最短路径呢?

通过递归的方式能够来寻找最短路径,跟二分递归类似,代码在下面已经实现了

一道简单的练习题

实现弗洛伊德-寻找最短路径

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 32767
#define OK 1
#define ERROR 0
typedef int Status;
typedef int ElemType;
typedef struct _Graph{
int vexNum;
int arcNum;
int** arcs;
char* vexs;
}Graph, *PGraph;
Graph* initGraph(int vexNum)
{
Graph* pGraph = NULL;
if (pGraph == NULL)
{
pGraph = (Graph*)malloc(sizeof(Graph));
memset(pGraph, 0, sizeof(Graph));
if (pGraph == NULL)
return NULL;
pGraph->vexNum = vexNum;
pGraph->vexs = (char*)malloc(sizeof(pGraph->vexNum));
memset(pGraph->vexs, 0, sizeof(pGraph->vexNum));
pGraph->arcNum = 0;
pGraph->arcs = (int**)malloc(sizeof(int*)* pGraph->vexNum);
memset(pGraph->arcs, sizeof(int*)* pGraph->vexNum, 0);
for (int i = 0; i < pGraph->vexNum; i++)
{
pGraph->arcs[i] = (int*)malloc(sizeof(int)* pGraph->vexNum);
memset(pGraph->arcs[i], 0, sizeof(int)*pGraph->vexNum);
}
}
return pGraph;
}
Status createGraph(Graph** pGraph, char* vexs, int* arcs)
{
if (*pGraph == NULL)
return ERROR;
for (int i = 0; i<(*pGraph)->vexNum; i++)
{
*((*pGraph)->vexs + i) = *(vexs + i);
for (int j = 0; j<(*pGraph)->vexNum; j++)
{
(*pGraph)->arcs[i][j] = *(arcs + i*((*pGraph)->vexNum) + j);
printf("%d ", (*pGraph)->arcs[i][j]);
if ((*pGraph)->arcs[i][j] != 0 && (*pGraph)->arcs[i][j] != MAX)
(*pGraph)->arcNum++;
}
printf("\n");
}
(*pGraph)->arcNum /= 2;
return OK;
}
// 深度优先遍历DFS
Status DFS(Graph* pGraph, int* iVisitedArray, int visitedIndex)
{
if (pGraph == NULL)
return ERROR;
iVisitedArray[visitedIndex] = 1;
printf("%c ", pGraph->vexs[visitedIndex]);
for (int i = 0; i<pGraph->vexNum; i++)
{
if (pGraph->arcs[visitedIndex][i] > 0 && !iVisitedArray[i] && pGraph->arcs[visitedIndex][i] != MAX)
DFS(pGraph, iVisitedArray, i);
}
return OK;
}
void getRecurShortestPath(Graph* pGraph, int* iShortArray, int vexIndex1, int vexIndex2){
if (*(iShortArray + (vexIndex1 * pGraph->vexNum) + vexIndex2) == -1)
printf(" >> %c", pGraph->vexs[vexIndex2]);
else
{
int iIndex = *(iShortArray + (vexIndex1 * pGraph->vexNum) + vexIndex2);
getRecurShortestPath(pGraph, iShortArray, vexIndex1, iIndex);
getRecurShortestPath(pGraph, iShortArray, iIndex, vexIndex2);
}
}
void getFloyd(Graph* pGraph)
{
int i, j, k;
int iShortArray[5][5] = { 0 }; // 记录最短路径
for (i = 0; i < pGraph->vexNum; i++) // 行的计数
{
for (j = 0; j < pGraph->vexNum; j++) // 列的计数
{
iShortArray[i][j] = -1;
}
}
// 这里的k代表的加入了哪个节点之后,
// 比如k=0的时候,就是加入顶点1之后的情况。
// k=1的时候,就是加入了顶点2之后的情况
// k=2的时候,就是加入了顶点3之后的情况,此时类推即可
for (k = 0; k < pGraph->vexNum; k++)
{
for (i = 0; i < pGraph->vexNum; i++) // 行
{
for (j = 0; j<pGraph->vexNum; j++) // 列
{
if (pGraph->arcs[i][j] >(pGraph->arcs[i][k] + pGraph->arcs[k][j]))
{
pGraph->arcs[i][j] = pGraph->arcs[i][k] + pGraph->arcs[k][j];
iShortArray[i][j] = k;
}
}
}
printf("===============加入顶点%d之后的情况=================\n", k + 1);
for (int q = 0; q < pGraph->vexNum; q++)
{
for (int p = 0; p < pGraph->vexNum; p++)
{
printf("%d ", iShortArray[q][p]);
}
printf("\n");
}
}
printf("shortestPath: %c", pGraph->vexs[0]);
getRecurShortestPath(pGraph, (int*)iShortArray, 0, 4);
}
int main()
{
int iVisited[5] = { 0 };
int initArcs[5][5] =
{
0, 10, MAX, 30, 100,
MAX, 0, 50, MAX, MAX,
MAX, MAX, 0, MAX, 10,
MAX, MAX, 20, 0, 60,
MAX, MAX, MAX, MAX, 0
};
char initVexs[6] = "12345";
Graph* pGraph = initGraph(5);
createGraph(&pGraph, initVexs, (int*)initArcs);
getFloyd(pGraph);
return 0;
}

posted @   zpchcbd  阅读(236)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示