SPFA算法
求一点到另外有通路的点权值最小的路径。
因为本人很喜欢C,所以SPFA算法就用C实现,代码有的地方可以优化。例如:层次遍历。
代码实现:
#include
#include
#include
#define MAX_LEN 20
#define TRUE 1
#define FALSE 0
#define INTMAX 0xFFFF
#define OK 1
#define ERROR 0
typedef char Type[MAX_LEN];///------顶点信息数组
int visit[MAX_LEN];///----标记是否被访问
int mark[MAX_LEN];///-----标记是否已经在队列中
typedef struct ArcNode{///-------邻接表节点
int adjvex;//---路径下标
int weight;//---每条路径权重
struct ArcNode * next;
}ArcNode;
typedef struct VNode{///--------邻接表头
Type data;//---顶点信息
int dist;//---最短距离
int len;//----路径长度
int path[MAX_LEN];//----路径数组
ArcNode * firstarc;//---指向邻接表节点
}VNode , AdjList[MAX_LEN];
typedef struct ALGraph{///----图
AdjList vertices;//---指向邻接表头
int vexnum;//---顶点数
int arcnum;//---弧数(边数)
//int kind;//---图的类型
}ALGraph;
//
typedef struct Node{ ///---------广度优先遍历----链表实现
Type CH;
int x;
struct Node * next;
}Node;
/
typedef struct Queue{ ///----------SPFA算法---栈
int front;
int rear;
int value[MAX_LEN+1];
}Queue;
void InitGraph( ALGraph * g )///---------------初始化有向图函数--------------------
{
int i ;
printf("请输入 顶点数 和 边数:\n");
scanf("%d %d",&g->vexnum , &g->arcnum);
printf("请输入 顶点信息 :\n");
for( i = 0 ; i < g->vexnum ; i ++){
scanf("%s",&g->vertices[i].data);
g->vertices[i].firstarc = NULL;
}
}
int LocateVex( ALGraph * g , Type v )///-----------------查找函数----------------
{
int i;
for( i = 0 ; i < g->vexnum ; i++){
if( (strcmp(v , g->vertices[i].data)) == 0 )
return i;
}
}
void CreateAdjList( ALGraph * g )///----------------------邻接表建立有向图函数--------------
{
int i , j , k , weight;
Type v1 , v2 ;
ArcNode * p ;
printf("请输入%d条弧的 两两关系 及 权重 :\n",g->arcnum);
for( k = 0 ; k < g->arcnum ; k ++)
{
scanf("%s %s %d",&v1 , &v2 , &weight);
i = LocateVex( g , v1 );
j = LocateVex( g , v2 );
ArcNode * newnode = ( ArcNode * )malloc(sizeof(ArcNode));
newnode->adjvex = j;
newnode->weight = weight;
newnode->next = NULL;
p = g->vertices[i].firstarc;
if( p == NULL ){
g->vertices[i].firstarc = newnode;
}
else{
while( p->next )
p = p->next;
p->next = newnode;
}
}
}
///---------------------------------SPFA算法--栈的全部操作------------------------------------
void InitQueue( Queue * Q )
{
Q->front = Q->rear = 0;
}
int IsEmpty( Queue * Q )
{
return Q->front == Q->rear;
}
void Push( Queue * Q , int x )
{
Q->value[Q->rear] = x;
Q->rear = (Q->rear+1)%(MAX_LEN+1);
}
int Pop( Queue * Q )
{
if( IsEmpty( Q ))
return ERROR;
else{
int temp;
temp = Q->value[Q->front];
Q->front = (Q->front+1)%(MAX_LEN+1);
return temp;
}
}
void SPFA( ALGraph * g )///------------------------SPFA算法---(权值可以为负)------(邻接表实现)----------------------
{
int i ;
Visit( g );
Queue Q;
InitQueue( &Q );
g->vertices[0].dist = 0;
g->vertices[0].path[0] = 0;
mark[0] = TRUE;
Push( &Q , 0 );
while( !(IsEmpty( &Q )) ){
int temp = Pop( &Q );
mark[temp] = FALSE;
ArcNode * p;
p = g->vertices[temp].firstarc;
while( p ){
if( g->vertices[p->adjvex].dist > g->vertices[temp].dist + p->weight ){
g->vertices[p->adjvex].dist = g->vertices[temp].dist + p->weight;
GetNewPathWay( g , temp , p->adjvex );
if( mark[p->adjvex] != TRUE ){
Push( &Q , p->adjvex );
mark[p->adjvex] = TRUE;
}
}
p = p->next;
}
}
}
void GetNewPathWay( ALGraph * g , int j , int k )///-------------------更新最短路径-----------
{
int i;
for( i = 0 ; i <= g->vertices[j].len ; i ++)
g->vertices[k].path[i] = g->vertices[j].path[i];
g->vertices[k].path[i] = k;
g->vertices[k].len = g->vertices[j].len + 1;
}
void ShowPathWay( ALGraph * g )///------------------------打印最短路径----------------
{
int i , j , k ,temp ;
for( k = 1 ; k < g->vexnum ; k ++ ){
temp = 1;
for( i = 0 ; i <= g->vertices[k].len ; i++){
if( g->vertices[k].path[i] == k ){
printf("%s-->%s 的最短路径是 :" , g->vertices[0].data ,g->vertices[k].data);
for( j = 0 ; j < i ; j ++){
printf("%s->",g->vertices[g->vertices[k].path[j]].data);
}
printf("%s\n",g->vertices[k].data );
printf("距离为:");
printf("%d\n\n---------------------------------\n",g->vertices[k].dist);
temp = 0;
break;
}
}
if( temp == 1 ){
printf("\nERROR:\n");
printf("没有通路\n\n");
}
}
}
void Visit( ALGraph * g )///-------------初始化路径
{
int i,j;
for( i = 0 ; i vexnum ; i ++){
mark[i] = FALSE;
visit[i] = FALSE;
g->vertices[i].dist = INTMAX;
g->vertices[i].len = 0;
for( j = 0 ; j < g->vexnum ; j ++ )
g->vertices[i].path[j] = INTMAX;
}
}
///-----------------------------深度优先遍历函数-------
void Dfs( ALGraph * g , int i )
{
visit[i] = TRUE;
printf("%s ",g->vertices[i].data);
ArcNode * p;
p = g->vertices[i].firstarc;
while( p ){
if(!visit[p->adjvex])
Dfs( g , p->adjvex );
else
p = p->next;
}
}
void DfsTraverse( ALGraph * g )
{
int i;
Visit( g );
for( i = 0 ; i vexnum ; i ++)
if(!visit[i])
Dfs(g , i);
}
///-------------------------------------广度优先遍历---(链表实现)
Node * ListBfsTraverse( ALGraph * g , Node * Head )
{
int i;
ArcNode * p;
Head->next = NULL;
Node * Hnew = Head ,* first;
first = Hnew;
Visit( g );
for( i = 0 ; i vexnum ; i ++){
if(!visit[i])
{
Node * pnew = (Node *)malloc(sizeof(Node));
strcpy(pnew->CH , g->vertices[i].data);
pnew->x = i;
pnew->next = NULL;
Hnew->next = pnew;
Hnew = pnew;
visit[i] = TRUE;
p = g->vertices[i].firstarc;
while( p ){
if(!visit[p->adjvex])
{
Node * pnew = (Node *)malloc(sizeof(Node));
strcpy(pnew->CH , g->vertices[p->adjvex].data);
pnew->next = NULL;
pnew->x = p->adjvex;
Hnew->next = pnew;
Hnew = pnew;
visit[p->adjvex] = TRUE;
}
p = p->next;
}
first = first->next;
ArcNode * q;
while( first->next ){
q = g->vertices[first->x].firstarc;
while( q ){
if(!visit[q->adjvex])
{
Node * pnew = (Node *)malloc(sizeof(Node));
strcpy(pnew->CH , g->vertices[q->adjvex].data);
pnew->next = NULL;
pnew->x = q->adjvex;
Hnew->next = pnew;
Hnew = pnew;
visit[q->adjvex] = TRUE;
}
q = q->next;
}
first = first->next;
}
}
}
return Head;
}
void ShowList( Node * Head )
{
Node * p = Head;
while( p->next ){
p = p->next;
printf("%s ",p->CH);
}
printf("\n");
}
///---------------------测试函数---------------------------
void Indge( ALGraph * g )
{
int i ;
ArcNode * p ;
printf("\n------------------------测试邻接表-----------------------\n");
for( i = 0 ; i vexnum ; i ++){
printf("%s ----> ",g->vertices[i].data);
p = g->vertices[i].firstarc;
while( p ){
printf("%s ",g->vertices[p->adjvex].data);
printf("(%d) ",p->weight);
p = p->next;
}
printf("\n");
}
printf("\n");
}
int main()///----------------------------main()----------------
{
int T;
printf("------------有向图的建立与遍历----邻接表实现---------------------\n");
printf("请输入测试数据组数:\n");
scanf("%d",&T);
while( T -- )
{
ALGraph g;
printf("-------------------初始化--------------------\n");
InitGraph( &g );
printf("-----------------建立有向图------------------\n");
CreateAdjList( &g );
printf("\n\n深度优先遍历有向图:\n");
DfsTraverse( &g );
printf("\n\n广度优先遍历有向图:\n");
Node * HEAD = ( Node *)malloc(sizeof(Node));
HEAD = ListBfsTraverse( &g , HEAD );
ShowList( HEAD );
Indge( &g );
SPFA( &g );
ShowPathWay( &g );
printf("\n\n-----------------------------------------------------\n");
}
return 0;
}
案例:
------------有向图的建立与遍历----邻接表实现---------------------
请输入测试数据组数:
5
-------------------初始化--------------------
请输入 顶点数 和 边数:
8 10
请输入 顶点信息 :
1 2 3 4 5 6 7 8
-----------------建立有向图------------------
请输入10条弧的 两两关系 及 权重 :
1 2 3
1 3 5
2 4 2
2 5 8
3 2 -3
3 6 3
3 7 4
4 8 5
5 8 -4
7 6 -2
深度优先遍历有向图:
1 2 4 8 5 3 6 7
广度优先遍历有向图:
1 2 3 4 5 6 7 8
------------------------测试邻接表-----------------------
1 ----> 2 (3) 3 (5)
2 ----> 4 (2) 5 (8)
3 ----> 2 (-3) 6 (3) 7 (4)
4 ----> 8 (5)
5 ----> 8 (-4)
6 ---->
7 ----> 6 (-2)
8 ---->
1-->2 的最短路径是 :1->3->2
距离为:2
---------------------------------
1-->3 的最短路径是 :1->3
距离为:5
---------------------------------
1-->4 的最短路径是 :1->3->2->4
距离为:4
---------------------------------
1-->5 的最短路径是 :1->3->2->5
距离为:10
---------------------------------
1-->6 的最短路径是 :1->3->7->6
距离为:7
---------------------------------
1-->7 的最短路径是 :1->3->7
距离为:9
---------------------------------
1-->8 的最短路径是 :1->3->2->5->8
距离为:6
---------------------------------