本文仅供参考,严禁抄袭!
文章目录
实验目的
通过实现Dijkstra算法和Floyd-Warshall算法,理解各种情况下最短路径求解的基本思想,并通过堆优化理解算法的优化思想,熟练运用各种数据结构实现对图的存储。
实验要求及实验环境
实验要求
- 实现单源最短路径的 Dijkstra 算法,输出源点及其到其他顶点的最短路径长
度和最短路径 - 利用堆结构(实现的优先级队列),改进和优化 Dijkstra 算法的实现;
- 实现全局最短路径的 Floyd-Warshall 算法。计算任意两个顶点间的最短距离
矩阵和最短路径矩阵,并输出任意两个顶点间的最短路径长度和最短路径。 - 利用 Dijkstra 或 Floyd-Warshall 算法解决单目标最短路径问题:找出图中每
个顶点 v 到某个指定顶点 c 最短路径; - 利用 Dijkstra 或 Floyd-Warshall 算法解决单顶点对间最短路径问题:对于某
对顶点 u 和 v,找出 u 到 v 和 v 到 u 的一条最短路径 ; - (选做)利用 Floyd-Warshall 算法,计算有向图的可达矩阵,理解可达矩阵
的含义; - 以文件形式输入图的顶点和边,并显示相应的结果。要求顶点不少于 10 个,
边不少于 13 个; - 软件功能结构安排合理,界面友好,便于使用.
实验环境
Visual Studio 2019, Windows 10
设计思想(本程序中的用到的所有数据类型的定义,主程序的流程图及各程序模块之间的调用关系)
堆的数据结构
- 逻辑设计:二叉树
- 物理设计:结构体数组,数组的每个节点由weight(权值)和key(在原数组中的下标)组成。
- 操作:
Initial():初始化堆;
DeleteMin():删除堆中最小元素;
MakeNullHeap():将堆置空;
HeapEmpty():堆是否为空;
HeapFull():堆是否满;
Insert():将某一元素插入堆;
图的存储结构1
- 逻辑设计:邻接矩阵
- 物理设计:结构体MTGraph:其中包含存储顶点表的数组vertex,存储矩阵的二维数组,存储边和顶点数量的整型数n,e。
图的存储结构2
- 逻辑设计:邻接表
- 物理设计:结构体AdjGraph:结构体VertexNode存储的顶点表:verlist,其中VertexNode存储顶点信息和指向其出边的指针firstedge,边表节点由结构体EdgeNode组成,包括指向顶点的下标adjvex,边的权重cost,指向下一条边的指针next
流程图
调用关系
- 删除堆最小值DeleteMin()调用了HeapEmpty()函数;
- 堆优化Dijkstra函数DijkstrabyHeapPro()调用了MakeNullHeap(将堆置空),MatrixToLink(邻接矩阵转邻接表),Initial(初始化堆),DeleteMin(删除堆中最小值),Insert(将某一元素插入堆)五个函数;
- 求解单目标最短路径的Trans函数调用了DijkstraPro(Dijkstra算法的修改,使其可求单目标最短路径);
- 求两个顶点间最短路径的TwoVertex函数调用了FloydPro函数(Floyd算法的调整,使其只输出给定两顶点间的最短路径);
测试结果
用例:
输入(第一行两个数分别为顶点数和边数,第二行为两边的顶点及边之权重):
10 16
1 3 34 1 6 100 2 7 72 2 5 89 3 4 90 3 6 21 3 5 55 4 3 67 5 3 92 6 7 45 7 2 86 8 1 33 8 9 9 9 5 10 10 9 17 10 4 28
输出:
源代码
#include<iostream>
#include<vector>
#include<string>
#include<fstream>
#include<algorithm>
#include<stack>
#define Maxlength 200
#define Infinity 10000
#define HeapMaxSize 200
using namespace std;
typedef struct {
vector<int>vertex;
int Matrix[Maxlength][Maxlength];
int n, e;
}MTGraph;
typedef struct {
int weight, key;
}Elementype;//用于堆的一个数据类型
typedef struct {
Elementype elements[HeapMaxSize];
int n;
}HEAP;//堆的定义
typedef struct node {
int adjvex;
int cost;
struct node* next;
}EdgeNode;
typedef struct {
int vertex;
EdgeNode* firstedge;
}VertexNode;
typedef struct {
VertexNode verlist[Maxlength];
int n, e;
}AdjGraph;
void MakeNullHeap(HEAP& heap)//将堆置空
{
heap.n = 0;
}
bool HeapFull(HEAP heap)
{
return (heap.n == HeapMaxSize - 1);
}//判断堆是否为满
bool HeapEmpty(HEAP heap)//判断堆是否为空
{
return (!heap.n);
}
void Initial(HEAP& heap, int num, vector<int>V, int D[])//将堆初始化
{
int j;
for (int i = 0; i < num; i++)
{
j = heap.n + 1;
while ((j != 1) && (D[V[i]] < heap.elements[j / 2].weight))
{
heap.elements[j] = heap.elements[j / 2];
j /= 2;
}
heap.elements[j].weight = D[V[i]];
heap.elements[j].key = V[i];
heap.n++;
}
}
void DeleteMin(HEAP& heap)//删除最小元素
{
Elementype temp;
int parent = 1, child = 2;
if (!HeapEmpty(heap))
{
temp = heap.elements[heap.n--];
while (child <= heap.n)
{
if ((child < heap.n) && (heap.elements[child].weight > heap.elements[child + 1].weight))
{
child++;
}
if (temp.weight <= heap.elements[child].weight)
break;
heap.elements[parent] = heap.elements[child];
parent = child;
child *= 2;
}
heap.elements[parent] = temp;
}
}
void MatrixToLink(MTGraph matrix, AdjGraph& link)//邻接矩阵转邻接表
{
for (int i = 0; i < matrix.n; i++)
{
link.verlist[i].vertex = matrix.vertex[i];
link.verlist[i].firstedge = NULL;
link.n++;
for (int j = 0; j < matrix.n; j++)
{
if (matrix.Matrix[i][j] != 0)
{
EdgeNode* p = new EdgeNode, * q = link.verlist[i].firstedge;
if (q == NULL)
{
p->adjvex = j;
p->cost = matrix.Matrix[i][j];
p->next = NULL;
link.verlist[i].firstedge = p;
}
else
{
while (q->next != NULL)
q = q->next;
p->adjvex = j;
p->cost = matrix.Matrix[i][j];
p->next = NULL;
q->next = p;
}
link.e++;
}
}
}
}
void Insert(HEAP& heap, int i, int weight)//更新堆中最小节点
{
int j;
if (!HeapFull(heap))
{
j = heap.n + 1;
while ((j != 1) && (weight < heap.elements[j / 2].weight))
{
heap.elements[j] = heap.elements[j / 2];
j /= 2;
}
heap.elements[j].weight = weight;
heap.elements[j].key = i;
heap.n++;
}
}
void DijkstrabyHeapPro(MTGraph graph)//堆优化后的Dijkstra算法,时间复杂度为O(n*log e)
{
int min, temp, start;
int D[Maxlength];//存储最短路径
int path[Maxlength] = { 0 };
int visit[Maxlength] = { 0 };
HEAP heap;
MakeNullHeap(heap);
AdjGraph link;
MatrixToLink(graph, link);
vector<int>S; //存储已选顶点
vector<int>V;//存储未选定点
V = graph.vertex;
vector<int>::iterator k = V.begin();
cout << "请输入源点:";
cin >> start;
start--;
for (k = V.begin(); k != V.end();)
{
if (*k == start)
{
V.erase(k);
break;
}
else
++k;
}
for (int i = 0; i < graph.n; i++)
D[i] = graph.Matrix[start][i];
Initial(heap, V.size(), V, D);
for (int i = 1; i < graph.n; i++)
{
min = heap.elements[1].key;
while (visit[min] == 1)
{
DeleteMin(heap);
min = heap.elements[1].key;
}
if (visit[min] == 0)
{
DeleteMin(heap);
visit[min] = 1;
}
S.push_back(min);
for (k = V.begin(); k != V.end();)
{
if (*k == min)
{
V.erase(k);
break;
}
else
++k;
}
EdgeNode* p = link.verlist[min].firstedge;
while (p)
{
if (D[p->adjvex] > (D[min] + graph.Matrix[min][p->adjvex]))
{
D[p->adjvex] = D[min] + graph.Matrix[min][p->adjvex];
temp = p->adjvex;
path[temp] = min;
Insert(heap, p->adjvex, D[p->adjvex]);
}
p = p->next;
}
}
sort(S.begin(), S.end());
cout << "单源最短路径:";//打印最短路径
for (auto x : S)
if (D[x] != Infinity)
{
cout << start + 1 << "->" << x + 1 << ":" << D[x] << ", ";
}
cout << endl;
stack<int>SS;
int t;
for (int i = 0; i < graph.n; i++)
{
if (i != start)
{
cout << start + 1 << "到" << i + 1 << "的最短路径为:" << start + 1;
t = path[i];
while (t != 0)
{
SS.push(t);
t = path[t];
}
while (!SS.empty())
{
cout << "->" << SS.top() + 1;
SS.pop();
}
cout << "->" << i + 1 << endl;
}
}
}
//从文件中读入数据到邻接矩阵
void ReadInMatirx(MTGraph& graph)
{
ifstream in("map.txt");
int n,e;//读入的第一行,存储的是顶点信息;第二行,存储的是边信息
int a, b, c;
int i = 0, j = 0;
in >> n >> e;
graph.e = e; graph.n = n;
for (i=0;i<graph.n;i++)
{
graph.vertex.push_back(i);
}
for (int m = 0; m < graph.n; m++)
for (int l = 0; l < graph.n; l++)
graph.Matrix[m][l] = Infinity;
for (int m = 0; m < graph.n; m++)
graph.Matrix[m][m] = 0;
for(j=0;j<graph.e;j++)
{
in >> a >> b >> c;
graph.Matrix[a-1][b-1] = c;
}
in.close();
}
void Floyd(MTGraph graph)//Floyd算法求每个顶点间的最短路径
{
int A[Maxlength][Maxlength], path[Maxlength][Maxlength];
int i, j, k, vertex;
for (i = 0; i < graph.n; i++)
for (j = 0; j < graph.n; j++)
{
A[i][j] = graph.Matrix[i][j];
path[i][j] = j;
}
for (k = 0; k < graph.n; k++)
{
for (i = 0; i < graph.n; i++)
{
for (j = 0; j < graph.n; j++)
{
if (A[i][k] + A[k][j] < A[i][j] && A[i][k]!=0 &&A[k][j]!=0)
{
A[i][j] = A[i][k] + A[k][j];
path[i][j] = path[i][k];//记录路径
}
}
}
}
for (i = 0; i < graph.n; i++)
{
for (j = 0; j < graph.n; j++)
printf("%6d", A[i][j]);
cout << endl;
}
for (i = 0; i < graph.n; i++)//输出每个顶点间最短路径
{
for (j = 0; j < graph.n; j++)
{
if (A[i][j] != 0 && A[i][j] != Infinity)
{
cout << i + 1 << "到" << j + 1 << "的最短路径为:" << i + 1;
vertex = path[i][j];
while (vertex != j)
{
cout << "->" << vertex + 1;
vertex = path[vertex][j];
}
cout << "->" << vertex + 1 << endl;
}
}
}
}
void Warshall(MTGraph graph)//Warshall算法求可达矩阵
{
int A[Maxlength][Maxlength];
int i, j, k;
for (i = 0; i < graph.n; i++)
for (j = 0; j < graph.n; j++)
{
if (graph.Matrix[i][j] == Infinity)
A[i][j] = 0;
else
A[i][j] = graph.Matrix[i][j];
}
for (k = 0; k < graph.n; k++)
{
for (i = 0; i < graph.n; i++)
{
for (j = 0; j < graph.n; j++)
{
A[i][j] = A[i][j] || (A[i][k] && A[k][j]);
}
}
}
for (i = 0; i < graph.n; i++)
{
for (j = 0; j < graph.n; j++)
printf("%3d", A[i][j]);
cout << endl;
}
}
void DijkstraPro(MTGraph graph, int start)//Dijkstra算法的改动,使其可求单目标点的最短路径,大致思路是把邻接矩阵转置后应用Dijkstra
{
int min, temp;
int D[Maxlength];//存储最短路径
int path[Maxlength] = { 0 };
vector<int>S; //存储已选顶点
vector<int>V;//存储未选定点
V = graph.vertex;
vector<int>::iterator k = V.begin();
for (k = V.begin(); k != V.end();)
{
if (*k == start)
{
V.erase(k);
break;
}
else
++k;
}
for (int i = 0; i < graph.n; i++)
D[i] = graph.Matrix[start][i];
for (int i = 1; i < graph.n; i++)
{
min = V[0];
for (auto x : V)
{
if (D[x] < D[min])
{
min = x;
}
}
S.push_back(min);
for (k = V.begin(); k != V.end();)
{
if (*k == min)
{
V.erase(k);
break;
}
else
++k;
}
for (auto x : V)
{
if (D[x] > (D[min] + graph.Matrix[min][x]) && graph.Matrix[min][x]!=0)
{
D[x] = D[min] + graph.Matrix[min][x];
temp = x;
path[temp] = min;
}
}
}
sort(S.begin(), S.end());
int flag = 0;
cout << "单源最短路径:";
for (auto x : S)
{
if (D[x] != Infinity)
{
cout << x + 1 << "->" << start + 1 << ":" << D[x] << ", ";
flag = 1;
}
}
cout << endl;
int t;
if (flag)
{
for (auto i:S)
{
if (i != start && D[i]!= Infinity)
{
cout << i + 1 << "到" << start + 1 << "的最短路径为:" << i + 1;
t = path[i];
while (t != 0)
{
cout << "->" << t + 1;
t = path[t];
}
cout << "->" << start + 1 << endl;
}
}
}
else
cout << "无" << endl;
}
void Trans(MTGraph graph)//调用Dijkstra算法求单目标最短路径的函数
{
int dest;
MTGraph matrix=graph;
for (int i = 0; i < graph.n; i++)
{
for (int j = 0; j < graph.n; j++)
{
matrix.Matrix[j][i] = graph.Matrix[i][j];
}
}
cout << "请输入目标点:";
cin >> dest;
DijkstraPro(matrix, dest-1);
}
void FloydPro(MTGraph graph, int verx1,int verx2)//Floyd的改动,即只输出给定两顶点间的最短路径
{
int A[Maxlength][Maxlength], path[Maxlength][Maxlength];
int i, j, k, vertex;
for (i = 0; i < graph.n; i++)
for (j = 0; j < graph.n; j++)
{
A[i][j] = graph.Matrix[i][j];
path[i][j] = j;
}
for (k = 0; k < graph.n; k++)
{
for (i = 0; i < graph.n; i++)
{
for (j = 0; j < graph.n; j++)
{
if (A[i][k] + A[k][j] < A[i][j])
{
A[i][j] = A[i][k] + A[k][j];
path[i][j] = path[i][k];
}
}
}
}
if (A[verx1][verx2] != Infinity)
{
cout << verx1 + 1 << "到" << verx2 + 1 << "的最短路径长度为:" << A[verx1][verx2] << ",";
cout << "最短路径为:";
cout << verx1 + 1;
vertex = path[verx1][verx2];
while (vertex != verx2)
{
cout << "->" << vertex + 1;
vertex = path[vertex][verx2];
}
cout << "->" << verx2 + 1 << endl;
}
else
cout << verx1 + 1 << "到" << verx2 + 1 << "无最短路径" << endl;
if (A[verx2][verx1] != Infinity)
{
cout << verx2 + 1 << "到" << verx1 + 1 << "的最短路径长度为:" << A[verx2][verx1] << ",";
cout << "最短路径为:";
cout << verx2 + 1;
vertex = path[verx2][verx1];
while (vertex != verx1)
{
cout << "->" << vertex + 1;
vertex = path[vertex][verx1];
}
cout << "->" << verx1 + 1 << endl;
}
else
cout << verx2 + 1 << "到" << verx1 + 1 << "无最短路径" << endl;
}//FloydPro算法
void TwoVertex(MTGraph graph)//调用FloydPro的函数
{
int verx1, verx2;
cout << "请分别输入两个顶点:" << endl;
cin >> verx1 >> verx2;
FloydPro(graph,verx1-1,verx2-1);
}
int main()
{
MTGraph graph;
graph.n = 0; graph.e = 0;
ReadInMatirx(graph);
for (int i = 0; i < graph.n; i++)
{
for (int j = 0; j < graph.n; j++)
printf("%7d", graph.Matrix[i][j]);
cout << endl;
}
cout << "顶点表为:";
for (int k = 0; k < graph.n; k++)
cout << graph.vertex[k] + 1 << " ";
cout << endl;
DijkstrabyHeapPro(graph);
cout << "Floyd算法求所有顶点对间最短路径:"<<endl;
Floyd(graph);
cout << "Warshall算法求可达矩阵:"<<endl;
Warshall(graph);
cout << "调整后的Dijkstra算法求所有点到目标点的最短路径:"<<endl;
Trans(graph);
cout << "Floyed算法求最短路径:" << endl;
TwoVertex(graph);
return 0;
}