广州大学数据结构课程设计

  • 程序设计题目

交通查询系统设计(难度系数 1.5)

[问题描述]

     今天铁路交通网络非常发达,人们在出差、旅游时,不仅关注交通费用,还关注里程和时间。请按照下图设计一个交通查询系统,能够满足旅客查询从任一个城市到另一个城市的最短里程、最低花费、最短时间、最少中转次数等问题。

[基本要求]

设计合适的数据结构和算法编写程序完成上述功能,并具有查询界面,能够按照下拉菜单选项进行选择查询。

 

  • 算法所需的数据结构
  1. 邻接矩阵
  2. 弗洛伊德算法

Floyd算法是一个经典的动态规划算法。用通俗的语言来描述的话,首先我们的目标是寻找从点i到点j的最短路径。从动态规划的角度看问题,我们需要为这个目标重新做一个诠释:

从任意节点i到任意节点j的最短路径不外乎2种可能,1是直接从i到j,2是从i经过若干个节点k到j。所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。

  • 算法设计思想(流程图或者思维导图,并标注各模块对应的函数说明)

 

  • 代码实现

编辑对话框、定义变量及为函数添加处理程序

 

pch.h

// pch.h: 这是预编译标头文件。

// 下方列出的文件仅编译一次,提高了将来生成的生成性能。

// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。

// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。

// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。

#ifndef PCH_H

#define PCH_H

// 添加要在此处预编译的标头

#include "framework.h"

#endif //PCH_H

#include<iostream>

#include<iomanip>

using namespace std;

#define MaxInt 32767

#define MaxNum 20

typedef struct Data

{

int d;

int c;

double t;

int ch;

};

typedef struct

{

int vexs[MaxNum];//顶点表

Data arcs[7][7];//邻接矩阵

int vexnum, arcnum;//图的当前点数和边数

}myGraph;

void Init(myGraph& G);

void create_dis(myGraph& G);

void init(bool**& S, double**& D, int**& Path);

void Short_Floyddis(myGraph& G, bool**& S, double**& D, int**& Path);

void Short_Floydcost(myGraph& G, bool**& S, double**& D, int**& Path);

void Short_Floydtime(myGraph& G, bool**& S, double**& D, int**& Path);

void Short_Floydchange(myGraph& G, bool**& S, double**& D, int**& Path);

int shortDistance(double** D, int i, int j);

int shortCost(double** D, int i, int j);

double shortTime(double** D, int i, int j);

int shortChange(double** D, int i, int j);

pch.cpp

// pch.cpp: 与预编译标头对应的源文件

#include "pch.h"

// 当使用预编译的头时,需要使用此源文件,编译才能成功。

//初始化邻接矩阵

void Init(myGraph& G)

{

G.vexnum = 7; G.arcnum = 10;

for (int i = 1; i <= G.vexnum; ++i)

G.vexs[i - 1] = i;

for (int i = 0; i < G.vexnum; ++i)

for (int j = 0; j < G.vexnum; ++j)

{

G.arcs[i][j] = { MaxInt,MaxInt,MaxInt,MaxInt };

}

}

//邻接矩阵

void create_dis(myGraph& G)

{

Init(G);

G.arcs[0][1] = { 2553, 885,8.0,1 };

G.arcs[0][2] = { 695,202,2.3,1 };

G.arcs[0][3] = { 704,225,2.5,1 };

G.arcs[1][2] = { 511,148,1.5,1 };

G.arcs[1][4] = { 812,283,3.0,1 };

G.arcs[2][3] = { 349,112,1.2,1 };

G.arcs[2][5] = { 1579,495,5.0,1 };

G.arcs[3][6] = { 651,162,2.0,1 };

G.arcs[4][5] = { 2368,684,7.0,1 };

G.arcs[5][6] = { 1385,386,4.0,1 };

for (int i = 0; i < G.vexnum; ++i)

for (int j = 0; j < G.vexnum; ++j)

G.arcs[j][i] = G.arcs[i][j];

}

//使用一维数组模拟二维数组

void init(bool**& S, double**& D, int**& Path)

{

S = new bool* [MaxNum];

for (int i = 0; i < MaxNum; ++i)

{

S[i] = new bool[MaxNum];

}

D = new double* [MaxNum];

for (int i = 0; i < MaxNum; ++i)

{

D[i] = new double[MaxNum];

}

Path = new int* [MaxNum];

for (int i = 0; i < MaxNum; ++i)

{

Path[i] = new int[MaxNum];

}

}

//利用弗洛伊德(Floyd)算法求上图中城市间最短路径

void Short_Floyddis(myGraph& G, bool**& S, double**& D, int**& Path)

{

init(S, D, Path);//二维数组

int n = G.vexnum;

for (int i = 0; i < n; ++i)

for (int j = 0; j < n; ++j)

{

D[i][j] = G.arcs[i][j].d;

if (D[i][j] < MaxInt && i != j)Path[i][j] = i;//如果i和j之间有弧,则将j的前驱置为i,否则置为-1

else Path[i][j] = -1;

}

for (int k = 0; k < n; ++k)

for (int i = 0; i < n; ++i)

for (int j = 0; j < n; ++j)

if (D[i][k] + D[k][j] < D[i][j])//从i到k到j的一条路径更短

{

D[i][j] = D[i][k] + D[k][j];//更新D[i][j]

Path[i][j] = Path[k][j];//将j的前驱置为k

}

}

void Short_Floydcost(myGraph& G, bool**& S, double**& D, int**& Path)

{

init(S, D, Path);//二维数组

int n = G.vexnum;

for (int i = 0; i < n; ++i)

for (int j = 0; j < n; ++j)

{

D[i][j] = G.arcs[i][j].c;

if (D[i][j] < MaxInt && i != j)Path[i][j] = i;//如果i和j之间有弧,则将j的前驱置为i,否则置为-1

else Path[i][j] = -1;

}

for (int k = 0; k < n; ++k)

for (int i = 0; i < n; ++i)

for (int j = 0; j < n; ++j)

if (D[i][k] + D[k][j] < D[i][j])//从i到k到j的一条路径更短

{

D[i][j] = D[i][k] + D[k][j];//更新D[i][j]

Path[i][j] = Path[k][j];//将j的前驱置为k

}

}

void Short_Floydtime(myGraph& G, bool**& S, double**& D, int**& Path)

{

init(S, D, Path);//二维数组

int n = G.vexnum;

for (int i = 0; i < n; ++i)

for (int j = 0; j < n; ++j)

{

D[i][j] = G.arcs[i][j].t;

if (D[i][j] < MaxInt && i != j)Path[i][j] = i;//如果i和j之间有弧,则将j的前驱置为i,否则置为-1

else Path[i][j] = -1;

}

for (int k = 0; k < n; ++k)

for (int i = 0; i < n; ++i)

for (int j = 0; j < n; ++j)

if (D[i][k] + D[k][j] < D[i][j])//从i到k到j的一条路径更短

{

D[i][j] = D[i][k] + D[k][j];//更新D[i][j]

Path[i][j] = Path[k][j];//将j的前驱置为k

}

}

void Short_Floydchange(myGraph& G, bool**& S, double**& D, int**& Path)

{

init(S, D, Path);//二维数组

int n = G.vexnum;

for (int i = 0; i < n; ++i)

for (int j = 0; j < n; ++j)

{

D[i][j] = G.arcs[i][j].ch;

if (D[i][j] < MaxInt && i != j)Path[i][j] = i;//如果i和j之间有弧,则将j的前驱置为i,否则置为-1

else Path[i][j] = -1;

}

for (int k = 0; k < n; ++k)

for (int i = 0; i < n; ++i)

for (int j = 0; j < n; ++j)

if (D[i][k] + D[k][j] < D[i][j])//从i到k到j的一条路径更短

{

D[i][j] = D[i][k] + D[k][j];//更新D[i][j]

Path[i][j] = Path[k][j];//将j的前驱置为k

}

}

//最短里程

int shortDistance(double** D, int i, int j)

{

i--; j--;

return D[i][j];

}

//最低花费

int shortCost(double** D, int i, int j)

{

i--; j--;

return D[i][j];

}

//最短时间

double shortTime(double** D, int i, int j)

{

i--; j--;

return D[i][j];

}

//最少中转次数

int shortChange(double** D, int i, int j)

{

i--; j--;

return D[i][j] - 1;

}

inquireDlg.cpp

void CinquireDlg::OnClickedButtonQuire()

{

// TODO: 在此添加控件通知处理程序代码

myGraph G;

create_dis(G);

UpdateData(TRUE);//刷新数据,如果UpdateData(TRUE) == 将控件的值赋值给成员变量;UpdateData(FALSE) == 将成员变量的值赋值给控件。

m_start;

m_end;

UpdateData(FALSE);

bool** Sd, ** Sc, ** St, ** Sch;  int** Pathd, ** Pathc, ** Patht, ** Pathch;

double** Dd, ** Dc, ** Dt, ** Dch;

Short_Floyddis(G, Sd, Dd, Pathd);

Short_Floydcost(G, Sc, Dc, Pathc);

Short_Floydtime(G, St, Dt, Patht);

Short_Floydchange(G, Sch, Dch, Pathch);

UpdateData(TRUE);

m_dis = shortDistance(Dd, m_start+1, m_end+1);

m_cost = shortCost(Dc, m_start+1, m_end+1);

m_time = shortTime(Dt, m_start+1, m_end+1);

m_change = shortChange(Dch, m_start+1, m_end+1);

UpdateData(FALSE);

}

void CinquireDlg::OnBnClickedOk()

{

// TODO: 在此添加控件通知处理程序代码

CDialogEx::OnOK();

}

  • 测试数据与结果

1.测试数据:

里程邻接矩阵:

 

价格邻接矩阵:

 

时间邻接矩阵:

 

中转次数邻接矩阵:

  1. 测试结果

 

  

  • 时间复杂度与空间复杂度

时间复杂度:复杂度最高的是三次for循环中的if语句,时间复杂度为O(n^3).

空间复杂度:空间占用较大的是二维数组,空间复杂度为O(n^2).

  • 结束语(逐条给出课程设计过程中所遇到的主要困难及解决方案,不要写低级错误,不要人为制造错误)

1、一开始我是用迪杰斯特拉算法(作为主要算法)来实现的,但是我发现在进行查询的时候,每进行一次查询,都要调用迪杰斯特拉算法函数然后再进行结果输出,这样比较麻烦。后来我改用了弗洛伊德算法(更加简洁),直接运行算法函数生成最低权值和的二维数组,查询时直接调用输出函数(通过二维数组)得到结果。

2、我还试图用四个邻接矩阵来实现功能,后来采用结构体数组方法只使用一个邻接矩阵来进行操作.

3、一开始对MFC的控件使用不熟悉,将combox类型定义为int后其无法使用AddString函数输入数据,而应在属性处输入数据,并用分号隔开。

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值