//dijkstra.cpp
//Dijkstra算法的实现
//读入“DijkstraTxt”中的部分网络数据“Test.txt”(弧段起点ID,弧段终点ID,弧段距离)
//用Dijkstra算法生成的最佳路径再写入“RouteTxt.txt”文件中
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
using namespace std;
#define MAXIMUM 1000000000 //无穷大
typedef struct recordList
{
int startPoint; //起点
int endPoint; //终点
float length; //弧段长度
recordList *next; //结构体指针
} record; //定义Record结构体类型表示从文件中读取的数据记录
void main()
{
//打开Test.txt并从中读取数据
ifstream inPutFile("Test.txt", ios::in);
//以创建方式打开文件RouteTxt.txt并写入数据
ofstream outPutFile("RouteTxt.txt", ios::out);
if (!inPutFile || !outPutFile) //文件打开异常处理
{
cout << "文件打开失败!" << endl;
exit(1);
}
outPutFile << "\tDijkstra 算法实现结果数据\t" << endl;
outPutFile << "起点\t终点\t距离\t\t路径" << endl;
int numPoint; //点数
int numEdge; //边数
int maxPoint; //最大点号
record *head = NULL; //数据链表表头
record *data = NULL; //读取的一行数据
data = (record *)new record; //分配一行数据的内存空间
//读取一行数据,包括起点、终点、弧段长度
inPutFile >> data->startPoint >> data->endPoint >> data->length;
head = data; //数据链表表头指针
numEdge = 1; //初始边数为1
maxPoint = max(data->startPoint, data->endPoint); //初始最大点号
while (!inPutFile.eof()) //逐行读取文件中的数据到data中
{
data->next = (record *)new record; //动态分配内存空间
data = data->next; //指向下一个结构体
//读取一行数据,包括起点、终点、弧段长度,数据格式(弧段起点ID,弧段终点ID,弧段距离)
inPutFile >> data->startPoint >> data->endPoint >> data->length;
//若maxPiont小于起点或终点点号,更新maxPoint
if (maxPoint < data->startPoint)
maxPoint = data->startPoint;
if (maxPoint < data->endPoint)
maxPoint = data->endPoint;
numEdge++; //边数增加1
}
inPutFile.close(); //关闭文件流
data->next = NULL; //最后的指针赋值为空
/// 以上代码实现从文件读入数据,以下实现算法计算并写入结果到文件
int i, j, k; //变量
float *path = new float[maxPoint + 1]; //路径距离数组
int *route = new int[maxPoint + 1]; //路由表
bool *flag = new bool[maxPoint + 1]; //最短路径求取成功标记
for (i = 0; i <= maxPoint; i++) //按点号从小到大遍历所有结点做源结点
{
for (j = 0; j <= maxPoint; j++) //初始化路由表和路径距离数组
{
path[j] = MAXIMUM; //路径距离数组初始化为无穷大
route[j] = -1; //-1表示不能到达或最短路径尚未找出
flag[j] = false;
}
record *getData = head; //获得链表数据头指针
float minLength = MAXIMUM; //当前的最小距离
int lastPoint = i; //前一次找出的距离最短的路径的终点
while (getData != NULL) //遍历链表,找出源结点出发的最短路径
{
if (getData->startPoint == i) //起点为i
{
path[getData->endPoint] = getData->length; //获得源结点到目的结点的距离
route[getData->endPoint] = getData->startPoint; //路由信息存储为目的结点的前一个结点
if (minLength > getData->length) //距离小于当前最小距离
{
minLength = getData->length; //获得当前最小距离
lastPoint = getData->endPoint; //获得当前最小距离的终点
}
}
getData = getData->next; //指向下一个结构体
}
flag[lastPoint] = true; //标记起点到当前终点的最短路径已求出
for (k = 0; k < maxPoint; k++) //按点号从小到大遍历所有结点做目的结点
{
getData = head; //获得链表数据头指针
float tempLength = MAXIMUM; //当前的最小距离
int tempPoint = -1; //前一次找出的距离最短的路径的终点
while (getData != NULL) //遍历链表,更新路由信息和距离数组
{
if ((getData->startPoint == lastPoint) && (getData->endPoint != i) && !flag[getData->endPoint])
{ //起点为上一次最短路径的终点,终点与起点不同,最短路径未求出
if ((minLength + getData->length) < path[getData->endPoint]) //有更短的路径
{
path[getData->endPoint] = minLength + getData->length; //获得源结点到目的结点的距离
route[getData->endPoint] = getData->startPoint;
//路由信息存储为目的结点的前一个结点
}
}
getData = getData->next; //指向下一个结构体
}
for (j = 0; j < maxPoint; j++)
{ //遍历path数组,找出到最短路径尚未找出的终点的距离最小值
if (!flag[j] && tempLength >= path[j] && j != i)
{ //最短路径尚未找出,且距离比当前最小距离更小,起点和终点不同
tempLength = path[j]; //更新最小距离值
tempPoint = j; //更新当前最短路径的终点
}
}
lastPoint = tempPoint; //获得当前最小距离的终点
minLength = tempLength; //获得当前最小距离
flag[lastPoint] = true; //标记起点到当前终点的最短路径已求出
}
/// 下面先指定文件写入结果数据
for (j = 0; j <= maxPoint; j++) //从每一个结点出发
{
if (path[j] == MAXIMUM) //路径不可达,或者终点和起点重叠
{
//向文件写入信息
outPutFile << i << "\t" << j << "\t--\t\t--" << endl;
}
else
{
string strRoute; //路径信息
int r = route[j]; //第j个点为终点时其上一跳位置
while (r != i) //根据路由表反向查找路径信息
{
stringstream ss; //使用字符串流将int转化为string型
ss << r; //字符串流写入
strRoute = "->" + ss.str() + strRoute; //构建路径信息字符串
r = route[r]; //上一跳
}
//向文件写入数据 “起点 终点 距离 路径”
outPutFile << i << "\t" << j << "\t" << path[j] << "\t\t" << i << strRoute << "->" << j << endl;
}
}
}
outPutFile.close(); //关闭文件流
return;
}