1、手动输入数据检验算法
#include <stdio.h>
#include <stdlib.h>
#define max1 10000000; //原词条这里的值太大,导致溢出,后面比较大小时会出错
int a[1000][1000];
int d[1000]; //d表示源节点到该节点的最小距离
int p[1000]; //p标记访问过的节点
int i, j, k;
int m; //m代表边数
int n; //n代表点数
int main()
{
scanf("%d%d", &n, &m);
int min1;
int x, y, z;
for (i = 1; i <= m; i++)
{
scanf("%d%d%d", &x, &y, &z);
a[x][y] = z;
a[y][x] = z;
}
for (i = 1; i <= n; i++)
d[i] = max1;
d[1] = 0;
for (i = 1; i <= n; i++)
{
min1 = max1;
//下面这个for循环的功能类似冒泡排序,目的是找到未访问节点中d[j]值最小的那个节点,
//作为下一个访问节点,用k标记
for (j = 1; j <= n; j++)
if (!p[j] && d[j] < min1)
{
min1 = d[j];
k = j;
}
//p[k]=d[k]; // 这是原来的代码,用下一 条代码替代。初始时,执行到这里k=1,而d[1]=0
//从而p[1]等于0,这样的话,上面的循环在之后的每次执行之后,k还是等于1。
p[k] = 1; //置1表示第k个节点已经访问过了
for (j = 1; j <= n; j++)
if (a[k][j] != 0 && !p[j] && d[j] > d[k] + a[k][j])
d[j] = d[k] + a[k][j];
}
//最终输出从源节点到其他每个节点的最小距离
for (i = 1; i < n; i++)
printf("%d->", d[i]);
printf("%d\n", d[n]);
return 0;
}
2、有向图单源最短路径
#include <stdio.h>
int main()
{
int e[10][10],dis[10],book[10],i,j,n,m,t1,t2,t3,u,v,min;
int inf=99999999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
//读入n和m,n表示顶点个数,m表示边的条数
scanf("%d %d",&n,&m);
//初始化
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==j) e[i][j]=0;
else e[i][j]=inf;
//读入边
for(i=1;i<=m;i++)
{
scanf("%d %d %d",&t1,&t2,&t3);
e[t1][t2]=t3;
}
//初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
for(i=1;i<=n;i++)
dis[i]=e[1][i];
//book数组初始化
for(i=1;i<=n;i++)
book[i]=0;
book[1]=1;
//Dijkstra算法核心语句
for(i=1;i<=n-1;i++)
{
//找到离1号顶点最近的顶点
min=inf;
for(j=1;j<=n;j++)
{
if(book[j]==0 && dis[j]<min)
{
min=dis[j];
u=j;
}
}
book[u]=1;
for(v=1;v<=n;v++)
{
if(e[u][v]<inf)
{
if(dis[v]>dis[u]+e[u][v])
dis[v]=dis[u]+e[u][v];
}
}
}
//输出最终的结果
for(i=1;i<=n;i++)
printf("%d ",dis[i]);
getchar();
getchar();
return 0;
}
3、无向图单源最短路径
#define MAXSIZE 20
#define PLACENUM 12
#define INF 9999 // 此处定义999为无穷大
struct
{
int vexnum,arcnum; //节点数和边数
int vexs[MAXSIZE]; // 节点名
int arcs[MAXSIZE][MAXSIZE]; //俩个节点之间的值
} net;
/*补充的结构体net,2019.7.3*/
void Dijkstra(int x,int y) // x为源点,y为终点
{
int i,j,k;
int min;
int u; //下一个放入集合p的点
int dis[net.vexnum]; // 最短路径
int mark[net.vexnum]; // 被mark的便是已经遍历,未被mark的便是未遍历
/*首先进行最短路径初始化*/
for(i=0; i<net.vexnum; i++)
{
mark[i] = 0;
dis[i] = net.arcs[x][i];
}
mark[x]=1; // 标记源点
for(k=0; k<net.vexnum; k++) // for 大循环
{
min = INF; // min初始化最大值,便于后来数据替换(每一个点的出度入度判断)
/*寻找遍历到点联通路径(与之相连线的点)中权值最小的一条; 标记遍历点;*/
for(i=0; i<net.vexnum; i++)
{
if(mark[i]==0&&min>dis[i]) //判断未遍历点 且 被赋值的最短路径(dis[i]<INF),未被赋值的点 // 应当min==dis[i]=INF
{
min = dis[i]; //在已知赋值最短路径中,寻找权值最小的点并将他作为下一个遍历
u=i; //点u点
}
}
mark[u]=1; //标记u点,下面u修正将会以最短路径进行辐射
/*修正最短路径*/
for(i=0;i<net.vexnum;i++)
{
if(!mark[i]&&dis[i]>dis[u]+net.arcs[u][i]) // !mark[i]判断不去走回头路, // dis[i]>dis[u]+net.arcs[u][i]有俩个用途:①若u链接的是x源点没有赋值最短路径的点,那么这里可以赋值②若是赋值过的点,那么可以判断是上一个dis[i](此时是被赋值过的)是不是真正的最短路径,即修正。
{
dis[i] = dis[u] + net.arcs[u][i]; //若A->C比A->B->C更长那么A->B->C则是到C的最短路径,下图将解释。
}
}
}
printf("最短路径值为: %d",dis[y]);
}
4、输出最短路径节点
#include <stdio.h>
#define M 65535 //无穷大
#define N 5 //顶点数
//Dijkstra算法函数,求给定顶点到其余各点的最短路径
//参数:邻接矩阵、出发点的下标、结果数组、路径前一点记录
void Dijkstra(int Cost[][N], int v0, int Distance[], int prev[])
{
int s[N];
int mindis, dis;
int i, j, u;
//初始化
for (i = 0; i < N; i++)
{
Distance[i] = Cost[v0][i];
s[i] = 0;
if (Distance[i] == M)
prev[i] = -1;
else
prev[i] = v0;
}
Distance[v0] = 0;
s[v0] = 1; //标记v0
//在当前还未找到最短路径的顶点中,
//寻找具有最短距离的顶点
for (i = 1; i < N; i++)
{ //每循环一次,求得一个最短路径
mindis = M;
u = v0;
for (j = 0; j < N; j++) //求离出发点最近的顶点
if (s[j] == 0 && Distance[j] < mindis)
{
mindis = Distance[j];
u = j;
} // if语句体结束,j循环结束
s[u] = 1;
for (j = 0; j < N; j++) //修改递增路径序列(集合)
if (s[j] == 0 && Cost[u][j] < M)
{ //对还未求得最短路径的顶点
//求出由最近的顶点 直达各顶点的距离
dis = Distance[u] + Cost[u][j];
// 如果新的路径更短,就替换掉原路径
if (Distance[j] > dis)
{
Distance[j] = dis;
prev[j] = u;
}
} // if 语句体结束,j循环结束
} // i循环结束
}
// 输出最短路径
// 参数:路径前一点记录、出发点的下标、到达点下标
void PrintPrev(int prev[], int v0, int vn)
{
int tmp = vn;
int i, j;
//临时存路径
int tmpprv[N];
//初始化数组
for (i = 0; i < N; i++)
tmpprv[i] = 0;
//记录到达点下标
tmpprv[0] = vn + 1;
//中间点用循环记录
for (i = 0, j = 1; j < N; j++)
{
if (prev[tmp] != -1 && tmp != 0)
{
tmpprv[i] = prev[tmp] + 1;
tmp = prev[tmp];
i++;
}
else
break;
}
//输出路径,数组逆向输出
for (i = N - 1; i >= 0; i--)
{
if (tmpprv[i] != 0)
{ //排除0元素
printf("V%d", tmpprv[i]);
if (i) //不是最后一个输出符号
printf("-->");
}
}
printf("-->V%d", vn + 1);
}
//主函数
int main()
{
//给出有向网的顶点数组
char *Vertex[N] = {"V1", "V2", "V3", "V4", "V5"};
//给出有向网的邻接矩阵
int Cost[N][N] = {
{0, 10, M, 30, 100},
{M, 0, 50, M, M},
{M, M, 0, M, 10},
{M, M, 20, 0, 60},
{M, M, M, M, 0},
};
int Distance[N]; //存放求得的最短路径长度
int prev[N]; //存放求得的最短路径
int i;
//调用Dijkstra算法函数,求顶点V1到其余各点的最短路径
//参数:邻接矩阵、顶点数、出发点的下标、 结果数组
Dijkstra(Cost, 0, Distance, prev);
for (i = 0; i < N; i++)
{
//输出最短路径长度
printf("%s-->%s:%d\t", Vertex[0], Vertex[i], Distance[i]);
//输出最短路径
PrintPrev(prev, 0, i);
printf("\n");
}
system("pause");
return 0;
}
执行结果:
5、完整手动输出的函数结果
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define INFINITY 65535
#define BEGIN -1
#define MAXVEX 100
#define NOTEXIST -1
#define TRUE 1
#define FALSE 0
int path[MAXVEX];
int dist[MAXVEX];
int known[MAXVEX];
typedef char VertexType;
typedef int WeightType;
typedef struct ENode
{
int ivex; //顶点 索引
WeightType weight;
struct ENode *next_edge;
} ENode;
typedef struct VNode
{
VertexType data; // 顶点 信息
ENode *first_edge;
} VNode;
typedef struct Graph
{
VNode vex[MAXVEX];
int vex_num, edge_num;
} Graph;
char read_char()
{
char ch;
do
{
ch = getchar();
} while (!isalpha(ch));
return ch;
}
int get_pos(Graph g, char ch)
{
int i;
for (i = 0; i < g.vex_num; i++)
{
if (ch == g.vex[i].data)
return i;
}
return -1;
}
void link_last(ENode *list, ENode *last)
{
ENode *p;
p = list;
while (p->next_edge != NULL)
{
p = p->next_edge;
}
p->next_edge = last;
}
void create_graph(Graph *g)
{
int i, w;
printf("请输入顶点数和边数:\n");
scanf("%d%d", &g->vex_num, &g->edge_num);
printf("请输入顶点信息:\n");
for (i = 0; i < g->vex_num; i++)
{
g->vex[i].first_edge = NULL;
g->vex[i].data = read_char();
}
printf("请输入边 :\n");
for (i = 0; i < g->edge_num; i++)
{
int p1, p2;
char c1, c2;
c1 = read_char();
c2 = read_char();
scanf("%d", &w);
p1 = get_pos(*g, c1);
p2 = get_pos(*g, c2);
ENode *node1;
node1 = (ENode *)malloc(sizeof(ENode));
if (node1 == NULL)
{
printf("error");
return;
}
node1->next_edge = NULL;
node1->ivex = p2;
node1->weight = w;
if (g->vex[p1].first_edge == NULL)
g->vex[p1].first_edge = node1;
else
link_last(g->vex[p1].first_edge, node1);
}
}
int get_weight(Graph g, int start, int end)
{
ENode *node;
if (start == end)
{
return 0;
}
node = g.vex[start].first_edge;
while (node != NULL)
{
if (end == node->ivex)
{
return node->weight;
}
node = node->next_edge;
}
return INFINITY;
}
void print_graph(Graph g)
{
int i;
ENode *p;
for (i = 0; i < g.vex_num; i++)
{
printf("%c", g.vex[i].data);
p = g.vex[i].first_edge;
while (p != NULL)
{
printf("(%c, %c)->w =%d ", g.vex[i].data, g.vex[p->ivex].data, p->weight);
p = p->next_edge;
}
printf("\n");
}
}
void init_graph(Graph g, int start)
{
int i;
for (i = 0; i < g.vex_num; i++)
{
// dist[i] = get_weight(g, start, i);//如果最开始 就获取起始点的临节点
path[i] = BEGIN; //需要改变相应临节点的path 值
known[i] = FALSE;
dist[i] = INFINITY;
}
dist[start] = 0;
//known[start] = TRUE;
}
int find_min(Graph g)
{
int i;
int index;
int min;
min = INFINITY; //每次初始为INFINITY
for (i = 0; i < g.vex_num; i++)
{
if (dist[i] < min && known[i] == FALSE)
{
min = dist[i];
index = i;
}
}
if (min == INFINITY)
return NOTEXIST;
else
{
return index;
}
}
void Dijkstra(Graph g)
{
ENode *p;
int v;
while (1)
{
v = find_min(g);
if (v == NOTEXIST)
break;
known[v] = TRUE;
p = g.vex[v].first_edge;
while (p != NULL)
{
if (known[p->ivex] == FALSE)
{
if (dist[v] + p->weight < dist[p->ivex])
{
dist[p->ivex] = dist[v] + p->weight;
path[p->ivex] = v;
}
}
p = p->next_edge;
}
}
}
void print_path2(Graph g, int end) //这里 直接传递最后位置的索引 类比树 的后续遍历
{
if (path[end] != BEGIN)
{
print_path2(g, path[end]);
printf("->");
}
printf("%c ", g.vex[end].data);
}
int main()
{
Graph g;
int start, end;
char ch1, ch2;
create_graph(&g);
printf("请输入起始点与终点:\n");
ch1 = read_char();
ch2 = read_char();
start = get_pos(g, ch1);
end = get_pos(g, ch2);
init_graph(g, start);
Dijkstra(g);
if (dist[end] == INFINITY)
printf("\n该两点间无路径.");
else
{
printf("最短路径为:\n\n");
print_path2(g, end);
printf("\n\n最小花费 : %d", dist[end]);
}
getchar();
getchar();
return 0;
}
附录算法
/*************************************************************************************************************
** 弗洛伊德(Floyd)算法
** 核心:是一种尝试的想法,从v到w只有两种方案:
1:直接从v到w,即DFloyd[v][w]
2:经过“另外的一个点”u,从v到w,即DFloyd[v][u] + DFloyd[u][w]
比较两种方案,取更小的
1:比较 :DFloyd[v][u] + DFloyd[u][w] < DFloyd[v][w]
2:取更小的:DFloyd[v][w] = DFloyd[v][u] + DFloyd[u][w]
** 这里的Path矩阵的构造很巧,关于Path矩阵代码仅仅只有几行而已!!!下面分析Path矩阵
1:矩阵Path的初值则为各个边的终点顶点-----相当于直接从v到w(上面两种方案的第一种)
2:当且仅当通过“另外一个点”的时候,有更短路径,即更新路径Path[v][w],把“另外一个点”放进Path[v][w]里
** 路径输出
1:不防把起点(G.vexs[i]),和Path[i][j]先输出(Path[i][j]是路径的第一个点)
2:循环输出直到(Path[temp][j] == j)为止!!!
** 自己可能还没有讲清楚,不用担心我在画个图解释下
请参考:https://mp.csdn.net/mdeditor/80579845
****************************************************************************************************************/
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#define MAXV 100
// #define INF 9999
typedef struct
{
double edges[MAXV][MAXV];
int n, e;
} MGraph;
void ppath(int path[][MAXV], int i, int j)
{
int k;
k = path[i][j];
if (k == -1)
return;
ppath(path, i, k);
printf("%d,", k);
ppath(path, k, j);
}
void DisPath(double A[][MAXV], int path[][MAXV], int n)
{
double INF = 9999;
int i, j;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
if (A[i][j] != INF && i != j)
{
printf(" 从%d到%d路径为:", i, j);
printf("%d,", i);
ppath(path, i, j);
printf("%d", j);
printf("\t路径长度为:%lf\n", A[i][j]);
}
}
void Floyd(MGraph g) //弗洛伊德算法从每对顶点之间的最短路径
{
double A[MAXV][MAXV];
int path[MAXV][MAXV];
int i, j, k, n = g.n;
for (i = 0; i < n; i++) //给A数组置初值
for (j = 0; j < n; j++)
{
A[i][j] = g.edges[i][j];
path[i][j] = -1;
}
for (k = 0; k < n; k++) //计算Ak
{
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
if (A[i][j] > (A[i][k] + A[k][j]))
{
A[i][j] = A[i][k] + A[k][j];
path[i][j] = k;
}
}
printf("\n输出最短路径:\n");
DisPath(A, path, n); //输出最短路径
}
void DispMat(MGraph g)
//输出邻接矩阵g
{
int i, j;
double INF = 9999;
for (i = 0; i < g.n; i++)
{
for (j = 0; j < g.n; j++)
if (g.edges[i][j] == INF)
printf("%3s", "∞");
else
printf("%lf", g.edges[i][j]);
printf("\n");
}
}
int main()
{
int i, j;
MGraph g;
double INF = 9999;
// double B[MAXV][6] = {
// {0, 5.0, INF, 7, INF, INF},
// {INF, 0, 4, INF, INF, INF},
// {8, INF, 0, INF, INF, 9},
// {INF, INF, 5, 0, INF, 6},
// {INF, INF, INF, 5, 0, INF},
// {3, INF, INF, INF, 1, 0}};
double B[MAXV][5] = {
{0, 50.623800, INF, INF, INF},
{50.623800, 0, 35.246200, INF, INF},
{INF, 35.246200, 0, 38.558400, INF},
{INF, INF, 38.558400,0, INF},
{INF, INF, INF, INF, 0},
};
g.n = 5;
g.e = 6;
for (i = 0; i < g.n; i++)
for (j = 0; j < g.n; j++)
g.edges[i][j] = B[i][j];
DispMat(g);
Floyd(g);
printf("\n");
system("pause");
return 0;
}
执行结果: