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