图论算法之最短路径(具有负边值的图)

1 算法介绍
如果图具有负边值,那么Dijkstra算法行不通。但是把赋权的和无权的算法结合起来将会解决这个问题。开始,我们把s放到队列中。然后,在每个阶段我们让一个顶点出队。找出所有与v邻接的顶点w,使得dw > dv + cvw。然后更新dw和pw,并在w不在队列中的时候把它放到队列中。
2 算法实现
//
//  main.c
//  WeightedNegative
//
//  Created by Wuyixin on 2017/6/11.
//  Copyright © 2017年 Coding365. All rights reserved.
//

#include <stdio.h>
#include "LinkList.h"
#include "Queue.h"

typedef LinkedList Graph,Vertex;


Graph initGraph(int n ,int g[n][n]);
void initArr(int n ,int g[n][n]);

/* 为了初始化方便,使用二维数组初始化图。实际上这是不允许的,因为使用链表就是为了避免使用二维数组*/
Graph initGraph(int n ,int a[n][n]){
    Graph g;
    Vertex v,w;
    
    g = malloc(n * sizeof(struct Node));
    if (g == NULL)
        exit(EXIT_FAILURE);
    
    /* 初始化顶点 */
    for (int i = 0; i < n; i++)  {
        g[i].data = i;
        g[i].next= NULL;
        g[i].dist = INT_MAX;
        g[i].known = 0;
        g[i].path = 0;
        g[i].cost = 0;
    }
    for (int i = 0; i < n; i++) {
        /* 构建顶点 */
        v = &g[i];
        for (int j = 0; j < n; j++) {
            /* 构建邻接顶点 */
            if (a[i][j] != UNAVAILABLE){
                w = malloc(sizeof(struct Node));
                if (w == NULL)
                    exit(EXIT_FAILURE);
                w->data = j;
                w->next = NULL;
                w->cost = a[i][j];
                
                v->next = w;
                v = w;
                
            }
        }
        
    }
    
    return g;
}
/* 初始化二维数组 */
void initArr(int n ,int g[n][n]){
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            g[i][j] = UNAVAILABLE;
    
}

void weightedNegative(Graph g,int n,int start){
    Queue q;
    Vertex v,w;
    
    q = createQueue(n);
    makeEmpty(q);
    
    g[start].dist = 0;
    
    
    enQueue(start, q);
    
    while (!isEmpty(q)) {
        v = &g[deQueue(q)];
        v->known = 1;
        for (w = v->next; w != NULL; w = w->next) {
            /* 找到比原来更短的距离,更新距离 */
            if (g[w->data].dist > v->dist + w->cost){
                g[w->data].dist = v->dist + w->cost;
                /* 更新path */
                g[w->data].path = v->data;
                if(!g[w->data].known)
                    enQueue(w->data, q);
            }
        }
    }
    
    disposeQueue(q);
    
}

void printDist(Graph g,int n){
    for (int i = 0 ; i < n; i++)
        printf("v%d--dist:%d  ",i,g[i].dist);
    printf("\n");
}



int main(int argc, const char * argv[]) {
    int a[7][7];
    initArr(7, a);
    a[0][1] = 2;
    a[0][3] = 1;
    a[1][3] = 3;
    a[1][4] = -10;
    a[2][0] = 4;
    a[2][5] = 5;
    a[3][2] = 2;
    a[3][4] = 2;
    a[3][5] = 8;
    a[3][6] = 4;
    a[4][6] = 6;
    a[6][5] = 1;
    
    Graph g;
    g = initGraph(7, a);
    
    weightedNegative(g, 7, 0);
    printDist(g, 7);
    return 0;
}



3 附录 队列与链表
3.1 队列
(1)头文件
//
//  Queue.h
//  Unweighted
//
//  Created by Wuyixin on 2017/6/6.
//  Copyright © 2017年 Coding365. All rights reserved.
//

#ifndef Queue_h
#define Queue_h

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

typedef int ElemType;
typedef struct QueueRecord *Queue;

struct QueueRecord{
    int capacity;
    int front;
    int rear;
    int size;
    ElemType *array;
};
/* 是否空 */
int isEmpty(Queue q);
/* 是否满 */
int isFull(Queue q);
/* 创建队列 */
Queue createQueue(int maxElement);
/* 销毁队列 */
void disposeQueue(Queue q);
/* 置空 */
void makeEmpty(Queue q);
/* 入队 */
void enQueue(ElemType x, Queue q);
/* 出队 */
ElemType deQueue( Queue q);
#endif /* Queue_h */

(2)实现文件

3.2 链表
(1)头文件
//
//  LinkList.h
//  Unweighted
//
//  Created by Wuyixin on 2017/6/6.
//  Copyright © 2017年 Coding365. All rights reserved.
//

#ifndef LinkList_h
#define LinkList_h

#include <stdio.h>
#include <limits.h>
#include <stdlib.h>

extern int UNAVAILABLE;
typedef struct Node *LinkedList,*PtoNode;
typedef int ElemType;
struct Node{
    ElemType data;
    struct Node* next;
    int dist;/* 路径长 */
    int known;/* 是否已入列 */
    int path;/* 上一个顶点 */
    int cost;/* 值 */
};

/* 链表初始化 */
LinkedList initList();
/* 插入元素 */
ElemType insert(ElemType x,LinkedList list);
/* 删除链表 */
void deleteList(LinkedList list);
/* 打印链表 */
void printList(LinkedList list);



#endif /* LinkList_h */


(2)实现文件
//
//  LinkList.c
//  Unweighted
//
//  Created by Wuyixin on 2017/6/6.
//  Copyright © 2017年 Coding365. All rights reserved.
//

#include "LinkList.h"


int UNAVAILABLE = INT_MIN;
/* 链表初始化 */
LinkedList initList(){
    LinkedList h = malloc(sizeof(struct Node));
    if (h == NULL)
        exit(EXIT_FAILURE);
    h->next = NULL;
    h->data = UNAVAILABLE;
    return h;
}
/* 插入元素 */
ElemType insert(ElemType x,LinkedList list){
    PtoNode current;
    current = list;
    while (current->next != NULL)
        current = current->next;
    
    
    /* 生成新节点 */
    PtoNode n = (PtoNode)malloc(sizeof(struct Node));
    if (n == NULL)
        exit(EXIT_FAILURE);
    
    n->data = x;
    n->next = NULL;
    
    current->next = n;
    
    
    return x;
}
/* 删除链表 */
void deleteList(LinkedList list){
    if (list == NULL)
        return;
    PtoNode node,old;
    node = list;
    while (node->next != NULL){
        old = node;
        node = node->next;
        free(old);
    }
}
/* 打印链表 */
void printList(LinkedList list){
    PtoNode node;
    node = list->next;
    while (node!= NULL ) {
        printf("%d ",node->data);
        node = node->next;
    }
    printf("\n");
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值