图论--SPFA算法---邻接表实现

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

---------------------------------

 

你可能感兴趣的:(数据结构,算法)