最近在写一个公交查询系统,输入的数据是一个文本文件,里面每一行是某个城市的公交线路的信息,即这条公交线路的站台信息。这个文件大致有3000行左右,总共站台数量大约为70000个。文件的第一列都是线路名称,后面的列都是站台信息。例如:
1路 东方明珠电视台 上海科技馆 上海南站 上海展览中心
2路环线 上海体育馆 上海南站 上海火车站 上海文化馆 上海体育馆
……
要求:输入两个站台,然后输出相应的可行的乘车方案,要求要么经过最少的站数,或者换乘的次数最少。
目前我已经写好程序了,颓废的代码写了3000行还要多。写完之后回头想想才发现原来这就是Dijkstra算法,自己从无到有地想清楚了解决了这个公交查询系统却不知道自己实现的就是多年前就已经成熟的图论算法:地杰斯特拉算法。真的很鄙视我自己,写了这么多年的算法却仍然不会运用到实践中来。回头看看Dijkstra算法的实现是多么精湛,后来还有带负权的Bellman-Ford算法,同样查找的是最短路径。查询系统抽象出来,无非也就是一个图而已,我目前要找的只是图中给定的两个节点的最短距离嘛,这和这个公交系统的运用的关联还是蛮直接的。据调查,在网络协议中的OSPF(Open Shortest Path First,开发最短路径优先)便是Dijkstra算法的一个最直接的运用。
这里有July大神的博客:http://blog.csdn.net/v_JULY_v/article/details/6096981
还有:http://www.cnblogs.com/heqinghui/archive/2012/07/26/2609563.html
此处贴上刚写的代码:
/*
* szldijkstra.h
*/
#ifndef SZL_DIJKSTRA_H
#define SZL_DIJKSTRA_H
void szl_dijkstra(int* graph[], int source, int destination);
#endif
/*
* szldijkstra.c
*/
#include "szldijkstra.h"
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void szl_dijkstra(int* graph[], int source, int destination);
int n,m;
int main( int argc ,char ** argv){
int **graph;
int i,j;
int u,v,w;
/*
* the source node and the destination node
*/
int s,d;
/*
* read from a file in the current directory named 'data.txt'
*/
FILE* data_file;
if( 1 == argc){
data_file=fopen("data.txt", "r");
}
else{
data_file=fopen(argv[1], "r");
}
assert(NULL!=data_file);
printf("input vertices and edges.\n");
fscanf(data_file,"%d%d",&n,&m);
/*
* implement a graph with matrix
*/
graph=(int **)malloc(sizeof(int *) * n);
assert(NULL != graph);
for(i=0;i<n;i++){
graph[i]=(int *)malloc(sizeof(int)*n);
assert(NULL!=graph[i]);
}
/*
* initialization the weight of the graph with a value which means this edge is not exists.
*/
for(i=0;i<n;i++){
for(j=0;j<n;j++){
graph[i][j]=INT_MIN;
}
}
/*
* input the edge and its weight
*/
for(i=0;i<m;i++){
printf("input edge %d:\n", (1+i));
fscanf(data_file,"%d%d%d",&u,&v,&w);
graph[u][v]=w;
}
/*
* get the starting node and the ending node
*/
printf("input destination = \n");
fscanf(data_file,"%d%d",&s,&d);
/*
* call the dijkstra to address it
*/
szl_dijkstra(graph,s, d);
/*
* close the input stream and free the memory allocated manually.
*/
fclose(data_file);
for(i=0;i<n;i++){
free(graph[i]);
}
free(graph);
return 0;
}
static int get_min(int a[], int infinite[], int in_set[], int n){
int min;
int min_index=-1;
int find=0;
int i;
for(i=0;i<n;i++){
if(infinite[i] == 0 && in_set[i] == 0){
if(find==0){
find++;
min=a[i];
min_index = i;
}
else{
if(min > a[i]){
min = a[i];
min_index = i;
}
}
}
}
return min_index;
}
void szl_dijkstra(int* graph[], int source, int destination){
/*
* store the predecessor of each node in the shortest path for print later.
*/
int *predecessor = (int *)malloc(sizeof(int)*n);
/*
* store the distance from the starting node to all the nodes in the graph
*/
int *dist=(int *)malloc(sizeof(int)*n);
/*
* indicate whether the distance value of a node is infinite or finite.
*/
int *dis_infinite = (int *)malloc(sizeof(int)*n);
/*
* indicate whether a node has been added to the set S.
* in our program, the program terminates when all the nodes have been added to
* set S. initially, no nodes is added to set S.
*/
int *in_set=(int *)malloc(sizeof(int)*n);
/*
* store the path, which can be evaluated from the predecessor array.
*/
int *stack=(int *)malloc(sizeof(int)*n);
int i,j;
int u,v,w;
int s=source;
//initialization
for(i=0;i<n;i++){
in_set[i] = 0;
predecessor[i] = -1;
dis_infinite[i] = 1;
dist[i] = 0;
}
/*
* the distance from source node to itself is zero, so it is not inifite large.
*/
dis_infinite[s] = 0;
//relax
u=-1;
for(i=0;i<n;i++){
/*
* each time we select a node from the nodes which is not in set S, with
* the smallest distance value.
*/
u = get_min(dist, dis_infinite, in_set, n);
if(u==destination){ /* we can return if we a node is the destination node early. */
break;
}
in_set[u] = 1; /* add it to set S. */
/*
* address all adjecent edges of the newly selected node.
*/
for(v=0;v<n;v++){
if(graph[u][v] > -1){ /* if (u,v) is an edge */
if(dis_infinite[v] != 0){ /* if this node has a infinite large distance. */
dist[v] = dist[u] + graph[u][v]; /* update it */
predecessor[v] = u; /* and modify its predecessor */
dis_infinite[v] = 0; /* modify its distance value to be a finite value. */
}
else if(dist[u]+graph[u][v] < dist[v]){ /* or if there exits smaller distance. */
dist[v] = dist[u] + graph[u][v]; /* update it */
predecessor[v] = u; /* and modify its predecessor */
dis_infinite[v] = 0; /* modify its distance value to be a finite value. */
}
}
}
}
//print
j=destination;
i=0;
while(predecessor[j] != -1){
stack[i++] = j;
j=predecessor[j];
}
stack[i] = j;
printf("path length = %d\n", dist[destination]);
for(j=i;j>=0;j--){
printf("%d",stack[j]);
if(j>0){
printf(", ");
}
}
//free
free(dist);
free(dis_infinite);
free(in_set);
free(stack);
free(predecessor);
}
另附一个测试文件data2.txt:
8 15
0 2 9
0 6 14
0 7 15
2 3 24
3 5 2
3 1 19
4 3 6
4 1 6
5 4 11
5 1 16
6 3 18
6 5 30
6 7 5
7 5 20
7 1 44
0 1
来源于这张图 (S节点是我输入的节点0,T节点是我输入的1节点):
在终端输入,并运行,结果为:
最后结果是正确的。