1、任务简述:
上网下载真实南京公交线路图,建立南京主要公交线路图的存储结构

要求:
(1)输入任意两站点,给出转车次数最少的乘车路线。
(2)输入任意两站点,给出经过站点最少的乘车路线。
(3)加分项:可以输出全部符合要求的乘车路线
2、算法描述:
站与站之间的图直接读取文件即可得到。而最小换乘需要一张车与车之间的图。在原本的站与站的图里,我在邻接表里存储了车的信息(可以知道每一条弧是哪一路车上的),可以方便后来构造车与车的图
最短路径算法:
未使用dijkstra算法而通过改进广度优先搜索来实现最短路径。
因为不论是站与站之间的图还是车与车之间的图,每一个结点之间权值都是1,将其联想到广度优先里一层一层搜索的思路。因为搜索完一层才会搜索下一层,所以最先搜索到终点的那一层肯定是最小层数(最少战点或最少换乘),肯定可以反向往上层查找找出一条最短路径。
实现方法是运用广度优先搜索里的visited数组,不用其表示是否访问过,而用其存储层数。广度搜索中队列每弹出一个站点,就搜索所有和该站点相邻的结点,如果未访问,就visited中置为1,表示访问过,然后进队列。这里改进为,visited置为当前层数+1。如果找到了终点,就结束广度搜索,并且用栈配合visited数组一层一层的往上找,最后将全部出栈,得出的就是一条最短路径。

图解:

3、源代码

#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string.h> #define STACK_INIT_SIZE 100
#define STACKINCREMENT 10using namespace std;/*以下为队列的结构定义*/
template <class T>
struct QNode
{T data;QNode* next;
};template <class T>
class Queue
{public:QNode<T>* front;   //队头指针(链表头)   QNode<T>* rear;   //队尾指针(链表尾) Queue(){front = rear = new QNode<T>;front->next = NULL;}~Queue(){QNode<T>* p, * q;p = q = front;while (p != NULL){p = p->next;delete q;q = p;}front = rear = NULL;}void ClearQueue(){QNode<T>* p, * q;p = q = front->next;while (p != NULL){p = p->next;delete q;q = p;}rear = front;}bool QueueEmpty(){if (front == rear){return true;}else{return false;}}int QueueLength(){int count = 0;QNode<T>* p;p = front->next;while (p != NULL){count++;p = p->next;}return count;}QNode<T>* GetHead(){if (front == rear){cout << "队空" << endl;return NULL;}else{return front->next;}}void EnQueue(T d){QNode<T>* p;p = new QNode<T>;p->data = d;p->next = NULL;rear->next = p;rear = rear->next;}T DeQueue(){if (front == rear){cout << "队空" << endl;}else{T ans;QNode<T>* p;p = front->next;ans = p->data;front->next = p->next;if (rear == p){rear = front;}delete p;return ans;}}};/*以下是栈的结构定义*/
template<class T>
class Stack
{private:T* data;T* base;T* top;int stacksize;
public:Stack(void){data = new T[STACK_INIT_SIZE];top = base = data;stacksize = STACK_INIT_SIZE;}void ClearStack(){top = base;}bool StackEmpty(){if (top == base){return true;}else{return false;}}int StackLength(){return top - base;}T GetTop(){return *(top - 1);}T* GetBaseLoca(){return base;}void Push(T num)      //进栈 {if (top - base != stacksize){*(top) = num;top++;}else{int i;T* tmp;tmp = new T[stacksize + STACKINCREMENT];for (i = 0; i < stacksize; i++){tmp[i] = data[i];}delete[]data;data = tmp;stacksize += STACKINCREMENT;*(top) = num;top++;}}T Pop()  //出栈 {if (top != base){top--;return *(top);}else{return '\0';}}void ShowStack(){int i;if (top - base == 0){cout << "空栈" << endl;}else{cout << "栈底到栈顶:";for (i = 0; i < top - base; i++){cout << data[i] << " ";}cout << endl;}}
};float min(float a, float b)
{if (a < b){return a;}else{return b;}
}struct ArcNode
{int adjvex;            //该弧所指向的顶点的位置vertices[adjvex]int road;          //表示这一条弧是第几路车,方便构建车与车之间的图ArcNode* nextarc;   //指向下一条弧的指针
};struct VNode
{char name[50];     //站点名ArcNode* firstarc; //指向第一条依附于该顶点的弧的指针
};class ALGraph {private:VNode vertices[6000];                   //顶点向量,每一站之间都有一个顶点int vexnum, arcnum;                       //图的当前顶点数和弧数int* visited;                           //用于深度优先搜索和广度优先搜索
public:void AddArcNode(int v1, int v2, int road)//为vertices[v1]和vertices[v2]两个站之间添加一条无向边,并且记录这一条无向边第road路上的{ArcNode* Ap;Ap = vertices[v1].firstarc;if (Ap == NULL){vertices[v1].firstarc = new ArcNode;vertices[v1].firstarc->adjvex = v2;vertices[v1].firstarc->road = road;vertices[v1].firstarc->nextarc = NULL;}else{while (Ap->nextarc != NULL){Ap = Ap->nextarc;}Ap->nextarc = new ArcNode;Ap = Ap->nextarc;Ap->adjvex = v2;Ap->road = road;Ap->nextarc = NULL;}Ap = vertices[v2].firstarc;if (Ap == NULL){vertices[v2].firstarc = new ArcNode;vertices[v2].firstarc->adjvex = v1;vertices[v2].firstarc->road = road;vertices[v2].firstarc->nextarc = NULL;}else{while (Ap->nextarc != NULL){Ap = Ap->nextarc;}Ap->nextarc = new ArcNode;Ap = Ap->nextarc;Ap->adjvex = v1;Ap->road = road;Ap->nextarc = NULL;}arcnum++;//边数++}ALGraph(){arcnum = 0;int i, j, count;int road;int pre_p;fstream rf;ArcNode* Ap;char str[3000];rf.open("南京公交线路.txt", ios::in);if (rf.fail()){cout << "南京公交线路.txt打开失败" << endl;exit(0);}vexnum = 0;road = 0;count = 0;while (!rf.eof()){rf >> road;if (rf.eof()){break;}rf.getline(str, 3000, '\n');i = 0;while (str[i] != ' ') i++;while (str[i] == ' ') i++;while (1){for (j = 0; str[i] != ',' && str[i] != '\0'; i++, j++){vertices[vexnum].name[j] = str[i];}vertices[vexnum].name[j] = '\0';for (j = 0; j < vexnum; j++){if (strcmp(vertices[j].name, vertices[vexnum].name) == 0){if (count > 0){AddArcNode(j, pre_p, road);}pre_p = j;count++;break;}}if (j == vexnum){vertices[vexnum].firstarc = NULL;if (count > 0){AddArcNode(pre_p, vexnum, road);}pre_p = vexnum;vexnum++;count++;}if (str[i] != '\0'){i++;}else{break;}}pre_p = 0;count = 0;}rf.close();visited = new int[vexnum];}~ALGraph(){ArcNode* Ap, * pre_Ap;for (int i = 0; i < vexnum; i++){Ap = vertices[i].firstarc;if (Ap == NULL);else{pre_Ap = Ap;while (1){Ap = Ap->nextarc;if (Ap == NULL){break;}delete pre_Ap;pre_Ap = Ap;}}}}ArcNode* AdjVex(int i){ArcNode* Ap;Ap = vertices[i].firstarc;if (Ap == NULL){return NULL;}else{return Ap;}}int GetVexNum(){return vexnum;}int FindRoad(char* n){for (int i = 0; i < vexnum; i++){if (strcmp(vertices[i].name, n) == 0){return i;}}return -1;}VNode* GetVNode(){return vertices;}bool IsAdj(int i, int j)//判断vertices[i]与vertices[j]是否相邻{ArcNode* Ap;Ap = vertices[i].firstarc;if (Ap == NULL);else{while (Ap != NULL){if (Ap->adjvex == j){return true;}Ap = Ap->nextarc;}}Ap = vertices[j].firstarc;if (Ap == NULL);else{while (Ap != NULL){if (Ap->adjvex == i){return true;}Ap = Ap->nextarc;}}return false;}void MiniRoad(char* start, char* end)         //用广度优先搜索求最短路径//start是起始站点的名字,end的是结束站点的名字{for (int i = 0; i < vexnum; i++){visited[i] = 0;}int v, u;int s, e;ArcNode* w = NULL;int i, j;int flag = 0;Queue<int> Q;for (i = 0; i < vexnum; i++){if (strcmp(start, vertices[i].name) == 0){s = i;}if (strcmp(end, vertices[i].name) == 0){e = i;}}v = s;visited[v] = 1;Q.EnQueue(v);while (!Q.QueueEmpty())//广度优先搜索{if (flag == 1){break;}u = Q.DeQueue();for (w = vertices[u].firstarc; w != NULL; w = w->nextarc){if (visited[w->adjvex] == 0){visited[w->adjvex] = visited[u] + 1;//往深一层搜索if (w->adjvex == e){flag = 1;//已经走到了终点break;}Q.EnQueue(w->adjvex);}}}ArcNode* Ap;Stack<int> S_sta;Stack<int> S_road;S_sta.Push(w->adjvex);i = w->adjvex;cout << "经过站最少的路线为:" << endl;cout << "共:" << visited[w->adjvex] << "站" << endl;for (int deep = visited[w->adjvex] - 1; deep > 1; deep--)//i是层数{for (j = 0; j < vexnum; j++)//j为下标{if (visited[j] == deep && IsAdj(i, j))//如果是上一层并且两站点相邻{S_sta.Push(j);//j可以在路线上,进栈i = j;//i成为上一层break;//结束循环并且往更上一层寻找}}}cout << vertices[s].name;i = s;while (!S_sta.StackEmpty())//输出路线{cout << "——>";j = S_sta.Pop();Ap = vertices[j].firstarc;while (Ap->adjvex != i){Ap = Ap->nextarc;}if (S_road.StackEmpty() || (S_road.GetTop() != Ap->road))//于此同时记录路线上的站点的乘车路线,并记录{S_road.Push(Ap->road);}cout << vertices[j].name;i = j;}cout << endl << endl;cout << "乘车路线为:" << endl;cout << "共:" << S_road.StackLength() << "路车" << endl;cout << S_road.Pop() << "路";while (!S_road.StackEmpty()){cout << "——>";cout << S_road.Pop() << "路";}cout << endl << endl;}};struct Arc
{int adjvex;            //该弧所指向的顶点的位置vertices[adjvex]Arc* nextarc;  //指向下一条弧的指针
};struct BusNode
{Arc* firstarc; //指向第一条依附于该顶点的弧的指针
};class LGraph//这个类是车与车之间的图
{private:BusNode vertices[1000];                         //顶点向量,从1开始int vexnum, arcnum;                       //图的当前顶点数和弧数int* visited;
public:void AddArc(int v1, int v2){int flag;Arc* Ap;Ap = vertices[v1].firstarc;if (Ap == NULL){vertices[v1].firstarc = new Arc;vertices[v1].firstarc->adjvex = v2;vertices[v1].firstarc->nextarc = NULL;}else{flag = 0;while (Ap->nextarc != NULL){if (Ap->adjvex == v2) flag = 1;//说明两辆车可以换乘的信息已经记录了Ap = Ap->nextarc;if (Ap->adjvex == v1) flag = 1;//说明两辆车可以换乘的信息已经记录了   }if (!flag){Ap->nextarc = new Arc;Ap = Ap->nextarc;Ap->adjvex = v2;Ap->nextarc = NULL;}}Ap = vertices[v2].firstarc;if (Ap == NULL){vertices[v2].firstarc = new Arc;vertices[v2].firstarc->adjvex = v1;vertices[v2].firstarc->nextarc = NULL;}else{flag = 0;while (Ap->nextarc != NULL){if (Ap->adjvex == v1) flag = 1;//说明两辆车可以换乘的信息已经记录了    Ap = Ap->nextarc;if (Ap->adjvex == v1) flag = 1;//说明两辆车可以换乘的信息已经记录了           }if (!flag){Ap->nextarc = new Arc;Ap = Ap->nextarc;Ap->adjvex = v1;Ap->nextarc = NULL;}}arcnum++;}LGraph(ALGraph* G)//用站与站之间的图来构建{vexnum = 0;ArcNode* Ap;Arc* Bp;int i, j, k;int count;int Bus[500];for (i = 0; i < G->GetVexNum(); i++){Ap = G->GetVNode()[i].firstarc;for (j = 0; j < 500; j++){Bus[j] = 0;}if (Ap == NULL){continue;}else{count = 0;while (Ap != NULL){for (k = 0; k < count; k++){if (Ap->road == Bus[k]){break;}}if (k == count){Bus[count++] = Ap->road;if (Ap->road > vexnum){vexnum = Ap->road;}}Ap = Ap->nextarc;}for (k = 0; k < count - 1; k++){for (j = k + 1; j < count; j++){if (Bus[j] != Bus[k]){AddArc(Bus[j], Bus[k]);}}}}}visited = new int[vexnum + 1];}~LGraph(){Arc* Ap, * pre_Ap;for (int i = 1; i < vexnum + 1; i++){Ap = vertices[i].firstarc;if (Ap == NULL);else{pre_Ap = Ap;while (1){Ap = Ap->nextarc;if (Ap == NULL){break;}delete pre_Ap;pre_Ap = Ap;}}}}bool IsAdj(int i, int j)//判断vertices[i]与vertices[j]是否相邻{Arc* Ap;Ap = vertices[i].firstarc;if (Ap == NULL);else{while (Ap != NULL){if (Ap->adjvex == j){return true;}Ap = Ap->nextarc;}}Ap = vertices[j].firstarc;if (Ap == NULL);else{while (Ap != NULL){if (Ap->adjvex == i){return true;}Ap = Ap->nextarc;}}return false;}int FindMinTime(int start, int end)         //从v开始进行广度优先搜索{if (start == end){return 0;}for (int i = 1; i < vexnum + 1; i++){visited[i] = 0;}int v, u;Arc* w = NULL;int i, j;int flag = 0;Queue<int> Q;v = start;visited[v] = 1;Q.EnQueue(v);while (!Q.QueueEmpty()){if (flag == 1){break;}u = Q.DeQueue();for (w = vertices[u].firstarc; w != NULL; w = w->nextarc){if (visited[w->adjvex] == 0){visited[w->adjvex] = visited[u] + 1;if (w->adjvex == end){flag = 1;//已经走到了终点break;}Q.EnQueue(w->adjvex);}}}return  visited[w->adjvex];}void PrintMinTransform(int start, int end){if (start == end){cout << "两站位于" << start << "路车路线上" << endl;return;}for (int i = 1; i < vexnum + 1; i++){visited[i] = 0;}int v, u;Arc* w = NULL;int i, j;int flag = 0;Queue<int> Q;v = start;visited[v] = 1;Q.EnQueue(v);while (!Q.QueueEmpty()){if (flag == 1){break;}u = Q.DeQueue();for (w = vertices[u].firstarc; w != NULL; w = w->nextarc){if (visited[w->adjvex] == 0){visited[w->adjvex] = visited[u] + 1;if (w->adjvex == end){flag = 1;//已经走到了终点break;}Q.EnQueue(w->adjvex);}}}Arc* Ap;Stack<int> S;S.Push(w->adjvex);i = w->adjvex;cout << "换成最少的路线为:" << endl;if (visited[w->adjvex] <= 2){cout << "不用换乘" << endl;}else{cout << "共换乘坐:" << visited[w->adjvex] - 1 << "次" << endl;}for (int deep = visited[w->adjvex] - 1; deep > 1; deep--)//i是层数{for (j = 0; j < vexnum; j++)//j为下标{if (visited[j] == deep && IsAdj(i, j)){S.Push(j);i = j;break;}}}cout << start;i = start;while (!S.StackEmpty()){cout << "——>";cout << S.Pop();}cout << endl << endl;}void MiniTransform(ALGraph* G, int start, int end)        //对G中每一个点都进行广度优先搜索{int i, j;for (i = 1; i < vexnum + 1; i++){visited[i] = 0;}ArcNode* Ap;int s_road[100];int e_road[100];int s_count = 0;int e_count = 0;char s[50];char e[50];Ap = G->GetVNode()[start].firstarc;while (Ap != NULL){s_road[s_count++] = Ap->road;Ap = Ap->nextarc;}Ap = G->GetVNode()[end].firstarc;while (Ap != NULL){e_road[e_count++] = Ap->road;Ap = Ap->nextarc;}int min = 99999;int tmp = 0;int min_s = 0;int min_e = 0;for (i = 0; i < s_count; i++){for (j = 0; j < e_count; j++){tmp = FindMinTime(s_road[i], e_road[j]);if (tmp <= min){min = tmp;min_s = s_road[i];min_e = e_road[j];}}}PrintMinTransform(min_s, min_e);}
};int main()
{int start, end;char s[50];char e[50];cout << "请输入起点:";cin >> s;cout << "请输入终点:";cin >> e;ALGraph A;LGraph B(&A);start = A.FindRoad(s);end = A.FindRoad(e);if (start == -1 || end == -1){cout << "输入站点有误!" << endl;return 0;}
if(start==end)
{cout << "\n不需要乘坐公交车,起点,终点位置相同!" <<endl;return 0;
}A.MiniRoad(s, e);cout << endl << endl << "最少换乘" << endl;B.MiniTransform(&A, start, end);
}//997行

4、运行结果
原始数据:



输入非法数据:

输入相同的合法数据:

5、总结
心得体会:
运行结果正确,不过该题难度较大,相比dijkstra对每一个点每一次循环都对每个点进行更新,广度搜索每个点只访问一次。缺点是由于数据结构的问题,我如果要在最少换乘输出在哪一站换乘会相对麻烦。或许在从站与站的图到车与车的图转换时,可以把中转点记录到邻接表中。
遇到问题和解决方法:
如果你们仔细看我的代码,你们会发现我只用了宽搜,没有用深搜,因为如果一条一条的遍历过去,那么实在是他花时间了,所以,我想出了一个新的思路:

数据结构课程设计(九)---公交线路提示相关推荐

  1. 公交换乘系统c语言,数据结构课程设计报告(公交换乘).docx

    课 程 设 计 报 告 题目: 武昌地区公交查询与换乘推荐 课程名称: 数据结构课程设计 专业班级: 学 号: 姓 名: 指导教师: 报告日期: 计算机科学与技术学院 任 务 书 设计内容 掌握图.查 ...

  2. 课程设计:公交线路管理系统

    #include <iostream> #include <string> #include<iomanip> #include <fstream> u ...

  3. 算法与数据结构课程设计城市公交管理系统(C、C++)

    城市公交管理系统 项目功能模块(需要源码请私信) 1.添加功能: [1]添加公交站,将站点信息写入stations.txt中: [2]添加交通路线,将路线信息写入bus.txt中: 2.删除功能: [ ...

  4. 数据结构课程设计 公交系统

    大家好! 这是我的第一篇文章,是将这学期的数据结构课设报告整理出来的.可能还有些小错误,还请多多指正. 数据结构课程设计<公交系统> 一.引言 (一)课题描述 (二)设计要求 二.总体设计 ...

  5. 数据结构课程设计4:公交线路提示

    1.任务: [问题描述] 上网下载真实南京公交线路图,建立南京主要公交线路图的存储结构. [基本要求] (1)输入任意两站点,给出转车次数最少的乘车路线. (2)输入任意两站点,给出经过站点最少的乘车 ...

  6. 基于数据结构和C语言实现公交管理系统(含文档和代码)数据结构课程设计

    目录 第1章 课程设计内容及要求 第2章 需求分析 第3章 算法设计 3.1 设计思想 3.2 设计表示 第4章 系统调试及测试(含代码) 4.1 功能截图 4.2 实现代码 第5章 课程设计心得 5 ...

  7. C/C++数据结构课程设计安排

    C/C++数据结构课程设计安排 数据结构课程设计安排 课程设计学时:32学时 课程设计目的:综合应用数据结构课程中所学的数据结构:线性表.栈.队列.数组.广义表.树.二叉树.图.查找表中的一种或多种数 ...

  8. 数据结构课程设计报告(附代码)

    数据结构课程设计报告 一.实训目的 通过课程设计,学会运用数据结构知识,针对具体应用,自己设计合理数据结构,确定存储结构,并能设计具体操作算法,选择使用具体语言进行实现.掌握C++较复杂程序的组织和设 ...

  9. 2018数据结构课程设计报告

    目录 一.引言 a) 编写目的 b) 项目背景 c) 术语说明 d) 参考资料 二.任务概述 a) 目标 b) 运行环境 c) 需求概述 d) 条件与限制 三. 总体设计 a) 处理流程 b) 总体结 ...

  10. 山东大学数据结构课程设计实验五(低风险出行系统)

    数据结构课程设计(五)--低风险出行系统 前言 题目要点 ①生成数据 ②要给定两种最短路解法 ③创立文件 ④模拟时间流动并与用户交互 代码讲解 源代码 写在最后 前言 数据结构课程设计第五题是每一个同 ...

最新文章

  1. tomcat 7/8 启动非常慢的解决方法
  2. centos7+ docker1.12 实践部署docker及配置direct_lvm
  3. 计算机应用英语考什么,网考计算机应用基础(本)试卷10(国外英语资料).doc
  4. 如何解决连接不上us.archive.ubuntu.com
  5. OpenAPI实现云主机闪电交付最佳实践
  6. 海龟绘图两小时上手C语言 - 0 引言
  7. Cmake之基本语法
  8. 小白记事本--JAVA入门
  9. 字符串数组排序,如果可以保证前一个字符的末尾与后一个字符的开头相同,返回1,否则返回-1...
  10. 百度程序题目----连续数问题
  11. 【Web前端】一文带你吃透HTML(完整篇)
  12. mysql 创建外部表_Greenplum
  13. python tkinter 窗口颜色--数据和名称
  14. 【转载】R6034错误,C Runtime Error
  15. Dataset之CV:人工智能领域数据集集合(计算机视觉CV方向数据集)之常见的计算机视觉图像数据集大集合(包括表面缺陷检测数据集,持续更新)
  16. 电子产品进水后如何处理
  17. 芯片刀片服务器,超微SuperBlade系列刀片服务器产品介绍
  18. 计算机程序存储在哪里,计算机正在运行的程序存放在哪里?
  19. RecyclerView---高仿网易新闻客户端
  20. windows虚拟机安装打印机的方式

热门文章

  1. **电脑不能启动故障诊断**
  2. 软件测试工程师面试接口测试常见问题
  3. 灰色关联分析(MATLAB)
  4. numpy_isnan函数
  5. 服务器搭建nexus启动成功 其他同一域下机器无法访问解决
  6. 微服务----2 mq+nacos
  7. vue去除富文本编辑器引起的<p>等标签
  8. Hive数据定义语言DDL
  9. 相机手动对焦(带动画效果)
  10. Pyecharts学习(一)