倘若我们要在计算机上建立一个交通咨询系统则可以采用图的结构来表示实际的交通网络。其实现最基本的功能,求出任意两点间的最短路径,
求最短路径的经典方法有很多种,最常用的便是迪杰斯特拉算法和佛洛依德(Floyd)算法,这篇文章就着重介绍Floyd算法。
求两点之间的最短路径无外乎有两种情况,一种就是从一点直接到另一点,另一种就是从一点经过n个节点后再到另一个节点,比如说要从A到B,则有两种情况就是A直接到B,或者是从A经过N个节点后再到B,所以,我们假设Dis(AB)为节点A到节点B的最短路径的距离,对于每一个节点X,我们检查Dis(AX)+Dis(XB)<Dis(AB)是否成立,如果成立,证明从A再到B的路径比A直接到B的路径短,我们便设置Dis(AB)=Dis(AX)+Dis(XB),这样一来,当我们遍历完所有节点X,Dis(AB)中记录的便是A到B的最短路径的距离。
直接上代码:
for(k = 0; k < Number; ++k)
{
for(i = 0; i < Number; ++i)
{
for(j = 0; j < Number; ++j)
{
if((Dis[i][k] + Dis[k][j]) < Dis[i][j])
{
// 找到更短路径
Dis[i][j] = Dis[i][k] + Dis[k][j];
}
}
}
}
那么接下来的问题就是,我们如何找出最短路径呢?这里需要借助一个辅助数组Path,它是这样使用的:Path(AB)的值如果为P,则表示A节点到B节点的最短路径是A->...->P->B。这样一来,假设我们要找A->B的最短路径,那么就依次查找,假设Path(AB)的值为P,那么接着查找Path(AP),假设Path(AP)的值为L,那么接着查找Path(AL),假设Path(AL)的值为A,则查找结束,最短路径为A->L->P->B。
那么,如何填充Path的值呢?很简单,当我们发现Dis(AX) + Dis(XB) < Dis(AB)成立时,就要把最短路径改为A->...->X->...->B,而此时,Path(XB)的值是已知的,所以,Path(AB) = Path(XB)。
下面的就是代码的具体实现了:
CreateGraphDemo.h
#ifndef __CREATE_GRAPH_DEMO_H
#define __CREATE_GRAPH_DEMO_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef false
#define false 0
#endif
#ifndef true
#define true 1
#endif
#ifndef error
#define error -1
#endif
#define INFINITY INT_MAX
#define MAX_VERTEX_NUM 20
#define MAX_INFO 100
#define MAX_NAME 10
typedefint VRType;
typedefchar InfoType;
typedefchar* VertexType;
VRType visited[MAX_VERTEX_NUM];
typedefenum{DG, DN, UDG, UDN} GraphKind;
typedefstruct ArcCell
{
VRType adj;//VRType是顶点关系类型,对无权图,用1或0表示相邻否,对带权图,则为权值类型
InfoType *info;//该弧相关信息的指针
}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedefstruct
{
VertexType vexs[MAX_VERTEX_NUM]; // 顶点向量
AdjMatrix arcs; // 邻接矩阵
VRType vexnum, arcnum; // 图的当前顶点数和弧数
GraphKind kind; // 图的种类标志
}MGraph;
//栈的结构
typedefstruct
{
VRType *base;
VRType *top;
}SqStack;
#ifdef __cplusplus
extern"C"{
#endif
//返回指定顶点elem在顶点向量中的位置
int LocateVex(MGraph G, VertexType elem);
//创建无向网
int CreateUDN(MGraph *G);
//创建有向图
int CreateDN(MGraph *G);
//显示其对应的邻接矩阵
int Display(MGraph *G);
//显示景点
int DisplayVexs(MGraph *G);
//释放空间
int FreeGraph(MGraph **G);
//最短路径算法
void FloydMethods(int Dis[][MAX_VERTEX_NUM], int Path[][MAX_VERTEX_NUM], int vexnum);
//输出最短路径以及路径长度
void ShowShortPath(int Dis[][MAX_VERTEX_NUM], int Path[][MAX_VERTEX_NUM], SqStack *S, MGraph *G);
//初始化栈
int InitStack(SqStack *S);
//压栈操作
int Push(SqStack *S, int e);
//出栈操作
int Pop(SqStack *S, int *e);
#ifdef _cplusplus
}
#endif
#endif
//CreateGraphDemo.c
#include "CreateGraphDemo.h"
int visited[20];
//返回指定顶点在顶点向量中的位置
int LocateVex(MGraph G, VertexType elem)
{
int i;
for(i = 0; i < G.vexnum; ++i)
if(strcmp(elem, G.vexs[i]) == 0)
return i;
return error;
}
void FloydMethods(int Dis[][MAX_VERTEX_NUM], int Path[][MAX_VERTEX_NUM], int _nVertexCount)
{
int i, j, k;
// 先初始化Path
for(i = 0; i < _nVertexCount; ++i)
{
for(j = 0; j < _nVertexCount; ++j)
{
Path[i][j] = i;
}
}
for(k = 0; k < _nVertexCount; ++k)
{
for(i = 0; i < _nVertexCount; ++i)
{
for(j = 0; j < _nVertexCount; ++j)
{
if((Dis[i][k] + Dis[k][j]) < Dis[i][j])
{
// 找到更短路径
Dis[i][j] = Dis[i][k] + Dis[k][j];
Path[i][j] = Path[k][j];
}
}
}
}
}
void ShowShortPath(int Dis[][MAX_VERTEX_NUM], int Path[][MAX_VERTEX_NUM], SqStack *S, MGraph *G)
{
int i, j, e, t, m, len = 0;
char Name1[10], Name2[10];
printf("\n请输入你想查找的两个景点名称 (两景点间用空格隔开) : ");
scanf("%s %s", Name1, Name2);
printf("起源 -> 目的地 最小距离 最短路径\n");
for(i = 0; i < G->vexnum; ++i)
{
for(j = 0; j < G->vexnum; ++j)
{
if(!strcmp(Name1, (*G).vexs[i]) && !strcmp(Name2, (*G).vexs[j]))
{
printf("%s -> %s\t", (*G).vexs[i], (*G).vexs[j]);
if(1000 == Dis[i][j]) // i -> j 不存在路径
{
printf("%s-->>%s is no road\n", (*G).vexs[i], (*G).vexs[j]);;
}
else
{
printf(" %d\t\t", Dis[i][j]);
int k = j;
do
{
k = Path[i][k];
Push(S, k);
len++;
}while(k != i);
Pop(S, &e);
printf("%s", (*G).vexs[e]);
t = e;
for(m = 0; m < len ; m++)
{
Pop(S, &e);
if(t != e)
{
printf(" -> %s", (*G).vexs[e]);
}
t = e;
}
printf(" -> %s\n", (*G).vexs[j]);
}
}
}
}
}
int InitStack(SqStack *S)
{
S->base = (int *)malloc(50*sizeof(int));
if(!S->base)
return error;
S->top = S->base;
returntrue;
}
int Push(SqStack *S, int e)
{
*(S->top++) = e;
returntrue;
}
int Pop(SqStack *S, int *e)
{
if(S->top == S->base)
returnfalse;
*e = *(--(S->top));
returntrue;
}
//无向网
int CreateUDN(MGraph *G)
{
int i, j, k, l, IncInfo, w;//IncInfo表示弧是否有其他信息
char s[MAX_INFO], *info;
char va[10], vb[10];
printf("请输入校园中的景点个数,所有景点之间的马路条数,景点是否含有其他信息(是:1,否:0)");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入每个景点的名称(<%d个字符):\n", MAX_NAME);
for(i = 0; i < (*G).vexnum; ++i)//构造顶点向量
{
(*G).vexs[i] = (VertexType)malloc(sizeof(char)*MAX_NAME);
scanf("%s", (*G).vexs[i]);
getchar();
}
for(i = 0; i < (*G).vexnum; ++i)//初始化邻接矩阵
{
for(j = 0; j < (*G).vexnum; ++j)
{
(*G).arcs[i][j].adj = 1000;
(*G).arcs[i][j].info = NULL;
}
}
printf("请输入%d条路中每条路所连接的两个景点(以空格隔开): \n", (*G).arcnum);
for(k = 0; k < (*G).arcnum; ++k)
{
scanf("%s %s", va, vb);//输入弧头,弧尾信息
printf("请输入该条路的长度 : ");
scanf("%d", &w);
i = LocateVex(*G, va);//定位弧尾位置,
j = LocateVex(*G, vb);//定位弧头位置
(*G).arcs[i][j].adj = w;//权值大小
(*G).arcs[j][i].adj = w;
if(IncInfo)
{
printf("请输入该景点的相关信息(<%d个字符) : ", MAX_INFO);
scanf("%s", s);
l = strlen(s);
if(l)
{
(*G).arcs[i][j].info = (char *)malloc((l+1)*sizeof(char));
strcpy((*G).arcs[i][j].info, s);
}
}
}
(*G).kind = DN;
returntrue;
}
//有向网
int CreateDN(MGraph *G)
{
int i, j, k, l, IncInfo, w;//IncInfo表示弧是否有其他信息
char s[MAX_INFO], *info;
char va[5], vb[5];
printf("请输入校园中的景点个数,所有景点之间的马路条数,景点是否含有其他信息(是:1,否:0)");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入每个景点的名称(<%d个字符)\n", MAX_NAME);
for(i = 0; i < (*G).vexnum; ++i)//构造顶点向量
{
(*G).vexs[i] = (VertexType)malloc(sizeof(char)*5);
scanf("%s", (*G).vexs[i]);
getchar();
}
for(i = 0; i < (*G).vexnum; ++i)//初始化邻接矩阵
for(j = 0; j < (*G).vexnum; ++j)
{
(*G).arcs[i][j].adj = 1000;
(*G).arcs[i][j].info = NULL;
}
printf("请输入%d条路中每条路所连接的两个景点(以空格隔开): \n", (*G).arcnum);
for(k = 0; k < (*G).arcnum; ++k)
{
scanf("%s %s", va, vb);//输入弧头,弧尾信息
printf("请输入该条路的长度 : ");
scanf("%d", &w);
i = LocateVex(*G, va);//定位弧尾位置,
j = LocateVex(*G, vb);//定位弧头位置
(*G).arcs[i][j].adj = w;//权值大小
if(IncInfo)
{
printf("请输入该景点的相关信息(<%d个字符) : ", MAX_INFO);
scanf("%s", s);
l = strlen(s);
if(l)
{
(*G).arcs[i][j].info = (char *)malloc((l+1)*sizeof(char));
strcpy((*G).arcs[i][j].info, s);
}
}
}
(*G).kind = DN;
returntrue;
}
int Display(MGraph *G)
{
int i, j;
printf("邻接矩阵输出 :\n");
for(i = 0; i < G->vexnum; i++)
{
for(j = 0; j < G->vexnum; j++)
{
printf("%d ", G->arcs[i][j].adj);
}
printf("\n");
}
}
int DisplayVexs(MGraph *G)
{
int i;
printf("---------------------景点:--------------------\n");
for(i = 0; i < G->vexnum; ++i)
{
printf("%s ", G->vexs[i]);
}
printf("\n------------------------------------------------\n\n");
}
int FreeGraph(MGraph **G)
{
int i, j;
for(i = 0; i < (*(*G)).vexnum; i++)
{
free((*G)->vexs[i]);
(*G)->vexs[i] = NULL;
for(j = 0; j < (*(*G)).vexnum; j++)
{
if((*G)->arcs[i][j].info)
{
free((*G)->arcs[i][j].info);
(*G)->arcs[i][j].info = NULL;
}
}
}
free(*G);
*G = NULL;
returntrue;
}
这是我之前写的一个校园导航的Demo,希望对大家有用……
//main.c
#include "CreateGraphDemo.h"
int main(int argc, char *argv[])
{
int i, j, a[20][20], b[20][20];
char ch;
SqStack S;
MGraph **p, *G = (MGraph *)malloc(sizeof(MGraph));
p = &G;
CreateUDN(G);
//CreateDN(G);
for(i = 0; i < G->vexnum; ++i)
{
for(j = 0; j < G->vexnum; ++j)
{
a[i][j] = G->arcs[i][j].adj;
}
}
InitStack(&S);
FloydMethods(a, b, G->vexnum);
loop:
DisplayVexs(G);
ShowShortPath(a, b, &S, G);
printf("Again ? (Y/N)\n");
getchar();
scanf("%c", &ch);
if('y' == ch || 'Y' == ch)
goto loop;
FreeGraph(p);
return 0;
}