基于图的数据结构实现的交通网查询系统
-
需求分析
问题描述:交通网查询系统的业务活动包括:添加城市信息、删除城市信息、修改城市信息、查询城市间路线等,通过图的数据结构来设计一个交通查网询系统,以使上述业务可以借助计算机来完成。 -
实现情况:采用图的数据结构,实现了中国交通网查询系统对于站点的增删改查功能。增:添加新的城市站点,根据经纬度的控制将其范围限制在中国境内;根据经纬度判断城市间实际路线长度,以此判断添加城市与其他城市间的关系是否符合实际情况。删:通过名称找到站点,删除站点以及站点和其他城市间的所有关系。改:可以改变城市间的关系以及城市本身的信息,例如站点开关,站点经纬度等。查:利用无向图位权图之间的查询方法,可以找到最短路径、最优价格方案、以及城市间所有的路线关系。显示:采用图形界面与用户交互,通过监控鼠标来控制。
-
编程环境:VS
-
编程语言:C语言
概要设计
- 所要用到的标准函数库文件
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <stack>
#include <queue>
#include<easyx.h>
#include<time.h>
#include<stdint.h>
#include <stddef.h>
- 自定义的头文件
#include "Insert_Functions.h"
#include "Search_Functions.h"
#include "Modify_Functions.h"
#include "Delete_Functions.h"
#include "Insert_Print_Info.h"
#include "Search_Print_Info.h"
#include "Modify_Print_Info.h"
#include "Delete_Print_Info.h"
#include "Display.h"
- 图的结构体:
typedef struct {
int n, e; //点数和边数
int arcs[N][N]; //点到点是否有相连关系
double distance[N][N]; //点到点之间的距离
char name[N][M]; //第i个点的名字
int statement[N]; //站点是否开放
double longtitude[N]; //经度
double latitude[N]; //纬度
double money[N][N]; //两点间价格
}MGraph;
- 数据宏定义
#define option_x 650
#define insert_x 650
#define insert_y 100
#define delete_x 650
#define delete_y 150
#define modify_x 650
#define modify_y 200
#define inquire_x 650
#define inquire_y 250
#define quit_x 650
#define quit_y 300
#define Length_cityname 20
#define modifyrelation_y 100
#define modifydistance_y 150
#define modifymoney_y 200
#define modifyopen_y 250
#define modifyname_y 300
#define modifylongtitude_y 350
#define modifylatitude_y 400
#define modifyquit_y 450
#define searchmindistance_y 100
#define searchminmoney_y 150
#define searchallroad_y 200
#define searchquit_y 250
- 定义常量
const int INF = 0x3f3f3f3f;
const int N = 110;
const int M = 20;
const double eps = 1e-6; //机器零
- 定义背景图
static IMAGE background;//背景
static IMAGE china;//中国轮廓图
程序模块
- 程序模块流程图:
-
方法函数接口
- 删除模块底层接口
int Delete_k(MGraph& G, int k);//删除第k个而且总个数自动减1
- 插入模块底层接口
int Insert_n(MGraph& G);//添加后点数加1,边数加2 int Insert_arcs(MGraph& G, int i, int j);//添加i和j之间的关系 int Insert_distance(MGraph& G, int i, int j, double dist);//添加i和j之间的距离 int Insert_money(MGraph& G, int i, int j, double money);//添加i和j之间的价格 int Insert_name(MGraph& G, int i, char name[]);//第i个名字的插入 int Open_statement(MGraph& G, int i);//开放第i个站点 int Close_statement(MGraph& G, int i);//关闭第i个站点 int Insert_longtitude(MGraph& G, int i, double num);//第i个站点插入经度 int Insert_latitude(MGraph& G, int i, double num);//第i个站点插入维度 ```
- 删除模块底层接口
-
修改模块底层接口
int Modify_arcs(MGraph& G, int i, int j, int k);//修改i和j之间的直接联系,边数减2 int Modify_distance(MGraph& G, int i, int j, double dist);//修改两站之间的距离 int Modify_money(MGraph& G, int i, int j, double money);//修改i和j之间的价格 int Modify_name(MGraph& G, int i, char name[]);//第i个点名字修改 int Modify_longtitude(MGraph& G, int i, double num);//修改第i个站点经度 int Modify_latitude(MGraph& G, int i, double num);//修改第i个站点维度 int Mopen_statement(MGraph& G, int i);//开放第i个站点 int Mclose_statement(MGraph& G, int i);//关闭第i个站点
-
查询模块底层接口
//求所有最短路径 int ShortestPath_Floyd(MGraph G, double d[N][N]); //path[N]存放路径,visited[N]存放是否遍历该点, v是起点(使用直接调用Find_Short_road函数) void Dijkstra(MGraph G, int v, int path[], int visited[]); //输入起点和终点,然后下标的先后顺序存放在road数组中(1开始存放)(直接开road) int Find_Short_road(MGraph G, int begin, int end, int road[]); //配合Find_All_Road函数使用(直接调用Find_All_Road函数) void DFS_road(MGraph G, int visited[], int begin, int end, int path[], double dist, int t, int a[N][N], int& cnt, double b[]); //查询符合方案的所有路径,递归 int Find_All_Road(MGraph G, int begin, int end, int a[N][N], double b[]); //配合Find_All_Money函数使用(直接调用Find_All_money函数) void DFS_money(MGraph G, int visited[], int begin, int end, int path[], double pay, int t, int a[N][N], int& cnt, double b[]); //查询符合方案的所有花费,递归 int Find_All_Money(MGraph G, int begin, int end, int a[N][N], double b[]); //path[N]存放路径,visited[N]存放是否遍历该点, v是起点(使用直接调用Find_Minimum_cost函数) void Dijkstra_money(MGraph G, int v, int path[], int visited[]); //输入起点和终点,然后下标的先后顺序存放在road数组中(1开始存放)(直接开road) int Find_Minimum_cost(MGraph G, int begin, int end, int road[]); //配合Find_All函数使用(直接调用 Find_All)函数) void DFS_All(MGraph G, int visited[], int begin, int end, int path[], double dist, double pay, int t, int a[N][N], int& cnt, double b[], double c[]); //所有下标从1开始 //输入起点begin终点end和一个存放二维数组(直接开a[N][N]),然后所有方案放在二维数组,一行为一个方案,列数为所有方案 //一个存放距离的值(直接开b[N])存放对应行数的距离 //一个存放花费的是c[N]存放对应行数的花费 int Find_All(MGraph G, int begin, int end, int a[N][N], double b[], double c[]); //查询站点状态 int Check_Station(MGraph G, int i);
-
实现函数接口
-
删除模块的信息输出功能实现
void deleteCityMessage(MGraph& G);
-
插入模块的信息输出功能
void insertCityMessage(MGraph& G); wchar_t GetInput();
- 修改模块的信息输出功能实现
void modifyCityRelation(MGraph& G); void modifyCityDistance(MGraph& G); void modifyCityMoney(MGraph& G); void modifyCityOpen(MGraph& G); void modifyCityName(MGraph& G); void modifyCityLongtitude(MGraph& G); void modifyCityLatitude(MGraph& G);
- 查询模块的信息输出功能实现
void searchMinDistanceRoad(MGraph& G); char* join1(char* a, char* b); double change(MGraph G, double num, int classes); void searchMinCostRoad(MGraph& G); void findAllRoad(MGraph& G);
- 地图模块的信息输出功能实现
void menu(MGraph &G); //找到名字返回下标,否则返回-1 int find_name(MGraph& G, char name[]); int InitMGraph(MGraph& G); void displayCity(MGraph G); void drawMainMenu(MGraph G); void modifyCityMessage(MGraph& G); void searchCityMessage(MGraph& G); void drawline(MGraph& G, int road[]);
-
用户手册及测试结果
-
系统说明:
用户界面根据图形界面输出,直观且美观,根据监控鼠标来判断用户选择什么功能(即通过鼠标点击控制选择对应模块),用户交互界面直观。 -
交通网初始界面:
-
点击鼠标控制选择功能模块
点击进入添加模块
-
点击删除城市信息进入删除模块
-
点击修改城市信息进入修改模块
修改模块包含7个子模块
-
点击进入查询路线功能
调试分析
(1) 删除时,删除掉某个站点后,站点个数减一,而导致最后一个站点丢失,解决方法是将站点前移(将后面数据上移和左移)
(2) 判断参数时,当数据为double类型时,应和机器零做比较
(3) 路径判断时,未对站点开关进行判断,从而导致站点关闭也会存在相应路径;解决方法,加入站点判断函数,进行控制路径查找。
(4) 当站点关闭或者开启时,未在地图上标明,地图上无法直观看出站点状态。解决方法:当站点关闭时,图标显示蓝色,开启时显示红色。
部分源码展示
//Delete_Functions.cpp
#include"Map.h"
//删除模块的实现功能
//删除第k个而且总个数自动减1
int Delete_k(MGraph& G, int k) {
if (k < 1 || k > G.n) return false;//非法输入
for(int i = 1 ; i <= G.n ; i ++ )
if(G.arcs[k][i])
G.e -= 2;
//左上为坐标零点,向右为i,向下为j,利用稍微开大的数组
// 在数据移动的时候同时也做了初始化边界操作
// 因此,在后续操作中G.n的大小必须满足
// G.n < N
//先从把后面的数据上移
for (int i = k; i <= G.n; i++) {
for (int j = 1; j <= G.n; j++) {
G.arcs[i][j] = G.arcs[i + 1][j];
G.distance[i][j] = G.distance[i + 1][j];
memcpy(G.name[i], G.name[i + 1], sizeof G.name[i + 1]);
G.statement[i] = G.statement[i + 1];
G.longtitude[i] = G.longtitude[i + 1];
G.latitude[i] = G.latitude[i + 1];
G.money[i][j] = G.money[i + 1][j];
}
}
//先从把后面的数据左移
for (int i = 1; i <= G.n; i++) {
for (int j = k; j <= G.n; j++) {
G.arcs[i][j] = G.arcs[i][j + 1];
G.distance[i][j] = G.distance[i][j + 1];
G.money[i][j] = G.money[i][j + 1];
}
}
G.n--;
return true;
}
//修改i和j之间的直接联系
int Modify_arcs(MGraph& G, int i, int j,int k) {//参数k存放两点之间关系,0表示修改成无联系,1表示修改成有联系
if (i < 1 || i > G.n || j < 1 || j > G.n) return false;//非法输入
if (k != 0 || k != 1) return false;//非法参数
if (k == 1) {
if (k == G.arcs[i][j]) {
return true;
}
else {
G.e += 2;
G.arcs[i][j] = G.arcs[j][i] = 1;
}
}
if (k == 0) {
if (k == G.arcs[i][j]) {
return true;
}
else {
G.e -= 2;
G.arcs[i][j] = G.arcs[j][i] = 0;
}
}
return true;
}
//修改两站之间的距离
int Modify_distance(MGraph& G, int i, int j, double dist) {
if (i < 1 || i > G.n || j < 1 || j > G.n) return false;
if (dist < 0) return false;//非法输入
G.distance[i][j] = G.distance[j][i] = dist;
return true;
}
//修改i和j之间的价格
int Modify_money(MGraph& G, int i, int j, double money) {
if (i < 1 || i > G.n || j < 1 || j > G.n) return false;
if (money < 0) return false;//非法输入
G.money[i][j] = G.money[j][i] = money;
return true;
}
//第i个点名字修改
int Modify_name(MGraph& G, int i, char name[]) {
if (i < 1 || i > G.n) return false;//非法输入
if (sizeof(name) > M) return false;//非法输入,参数过长
memcpy(G.name[i], name, sizeof name);
return true;
}
//修改第i个站点经度
int Modify_longtitude(MGraph& G, int i, double num) {
if (i < 1 || i > G.n) return false;
if (num < 73.33 || num > 135.05) return false;
G.longtitude[i] = num;
return true;
}
//修改第i个站点维度
int Modify_latitude(MGraph& G, int i, double num) {
if (i < 1 || i > G.n) return false;
if (num < 3.51 || num > 53.33) return false;
G.latitude[i] = num;
return true;
}
//开放第i个站点
int Mopen_statement(MGraph& G, int i) {
G.statement[i] = 1;
return true;
}
//关闭第i个站点
int Mclose_statement(MGraph& G, int i) {
G.statement[i] = 0;
return false;
}