图论算法之最短路径(有向无权图)

1.算法介绍
下图是一个无权图G。使用某个顶点s作为输入参数,我们想要找出从s到所有其他顶点的最短路径。

设我们选择s为v2.此时立刻可以说出从s到v2的最短路径长为0的路径。把这个信息做个标记。如下图。

现在我们可以开始找寻所有与s距离为1的顶点。这些顶点通过考查与s邻接的那些顶点可以找到。此时我们看到,v0和v5与s出发只有一步之遥。标记如下。


现在可以找出那些从s出发最短路径恰为2的顶点。找到所有邻接到v0和v5的顶点。它们的最短路径还不知道。这次搜索告诉我们,到v1和v3的最短路径长为2。标记如下。

最后,通过考查那些与刚被赋值的v1和v3相邻的顶点我们可以发现。v4和v6各有一条三边最短路径。标记如下。

这种搜索一个图的方法称为广度优先搜索。该方法按层处理顶点。距开始点最近的那些顶点首先被赋值。而最远的那些顶点最后被赋值。
2 算法实现
对于每个顶点。我们将跟踪三个信息。首先,我们把从s开始到顶点的距离放在dist中。开始的时候,除s外所有顶点都是不可达到的。另外我们记录引起顶点变化的最后一个节点path。最后如果顶点被处理过,将使用known标记。
算法的实现需要使用队列和链表。我把它们放在附录中。
核心算法是unWeighted函数initGraph和initArr负责初始化图G。

//
//  main.c
//  Unweighted2
//
//  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;
    }
    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;
                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 unWeighted(Graph g,int s,int n){
    if (g == NULL)
        exit(EXIT_FAILURE);
    Queue q;
    Vertex v,w,z;
    int i;
   
    q = createQueue(n);
    makeEmpty(q);
    g[s].dist = 0;
    g[s].known = 1;
    
    enQueue(s, q);
    
    while (!isEmpty(q)) {
        i = deQueue(q);
        v = &g[i];
        for (w = v->next; w != NULL; w = w->next) {
            z = &g[w->data];
            if (z->known == 0){
                z->dist = v->dist + 1;
                z->path = v->data;
                z->known = 1;
                enQueue(w->data, q);
            }
        }
        
    }
    
    disposeQueue(q);/* free queue */
}

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] = 1;
    a[0][3] = 1;
    a[1][3] = 1;
    a[1][4] = 1;
    a[2][0] = 1;
    a[2][5] = 1;
    a[3][2] = 1;
    a[3][4] = 1;
    a[3][5] = 1;
    a[3][6] = 1;
    a[3][4] = 1;
    a[4][6] = 1;
    a[6][5] = 1;
    
    Graph g;
    g = initGraph(7, a);
    
    unWeighted(g , 2, 7);
    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)实现文件

//
//  Queue.c
//  Unweighted
//
//  Created by Wuyixin on 2017/6/6.
//  Copyright © 2017年 Coding365. All rights reserved.
//

#include "Queue.h"

/* 是否空 */
int isEmpty(Queue q){
    return q->size == 0;
}
/* 是否满 */
int isFull(Queue q){
    return q->front % (q->capacity) == (q->rear + 2) % q->capacity;
}
/* 创建队列 */
Queue createQueue(int maxElement){
    if (maxElement <= 0)
        exit(EXIT_FAILURE);
    Queue q = malloc(sizeof(struct QueueRecord));
    if (q == NULL)
        exit(EXIT_FAILURE);
    
    ElemType* array = malloc(maxElement * sizeof(ElemType));
    if (array == NULL)
        exit(EXIT_FAILURE);
    q->array = array;
    q->capacity = maxElement + 1;
    makeEmpty(q);
    return q;
}
/* 销毁队列 */
void disposeQueue(Queue q){
    if (q != NULL){
        free(q->array);
        free(q);
    }
}
/* 置空 */
void makeEmpty(Queue q){
    q->size = 0;
    q->front = 1;
    q->rear = 0;
}
/* 入队 */
void enQueue(ElemType x, Queue q){
    if (!isFull(q)){
        q->rear = (q->rear + 1) % q->capacity;
        q->size += 1;
        q->array[q->rear] = x;
    }
}
/* 出队 */
ElemType deQueue(Queue q){
    if (!isEmpty(q)){
        int tmp = q->front;
        q->front = (q->front + 1) % q->capacity;
        q->size -= 1;
        return q->array[tmp];
    }
    
    return INT_MIN;
}



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;
};

/* 链表初始化 */
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");
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值