数据结构课程设计——项目2:校园导游咨询

这篇具有很好参考价值的文章主要介绍了数据结构课程设计——项目2:校园导游咨询。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、实验内容及实验要求

【问题描述】

设计一个校园导游程序,为来访的客人提供各种信息查询服务。

【基本要求】

  1. 设计你所在学校的校园平面图,所含景点不少于10个.以图中顶点表示校 内各景点,存放景点名称、代号、简介 等信息;以边表示路径,存放路径长度等相关信息。
  2. 为来访客人提供图中任意景点相关信息的查询。
  3. 为来访客人提供图中任意景点的问路查询,即查询任意两个景点之间的一条最短的简单路径。

【测试数据】

以江苏科技大学长山校区为例。

【实现提示】

一般情况下,校园的道路是双向通行的,可设校园平面图是一个无向网,顶点和边均含有相关信息.


二、问题分析

概述

  • 本实验的编程语言采用Java,并用Swing实现了GUI。用户可以点击校内景点的图片来查询该景点的详细信息,程序支持查询任意两景点间的最短路径,并可以根据初始点的位置提供推荐游览路径。
  • 数据结构采用了图的邻接矩阵存储,并且为了更加方便的实现Floyd算法,还提供了图的前趋结点数组。
  • 最短路径的查询采用了Floyd算法
  • 推荐游览路径即是从一个指定景点开始,不重复的游览完所有景点的路径,这一路径的计算采用了马踏棋盘算法,本质上采用了DFS图的深度优先遍历,另外还采用了贪心思想进行了优化。

最短路径——Floyd算法

Floyd算法可以给出网络中任意两个结点之间的最短路径,因此它是比Dijkstra更一般的算法。Floyd算法的思想是将n个结点的网络表示为n行n列的矩阵,而矩阵中的元素Di,j表示从结点i到结点j的距离,如果两点直接没有边相连,则相应的元素就是无穷∞。
具体过程描述如下:

a.从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。   
b.对于每一对结点 i 和 j,看看是否存在一个结点 k 使得从 i 到 k 再到 j 比己知的路径更短。如果是更新它,直到所有的结点都已经尝试过。

伪代码描述如下:

枚举顶点k ∈ [1,n]
	以顶点k为中介点,枚举所有顶点对i和j(i ∈ [1,n],j ∈1[1,n])
		如果dis[i][k] + dis[k][j] <dis[i][j]成立
			赋值dis[i][j] = dis[i][k] + dis[k][j]

注意Floyd算法为了能回溯得到最短路径的结果,需要声明一个前趋结点数组,用来保存所有点的前一个结点,每次找到更短的路径时,需要更新这一数组。

推荐游览路径——马踏棋盘算法

推荐游览路径是从一个指定景点开始,不重复的游览完所有景点的路径,即在图中寻找一条由指定结点开始的哈密尔顿路径。这一问题可以通过类似马踏棋盘问题的算法来解决,实质上是采用了图的深度优先遍历和贪心算法的优化。
该算法具体过程描述如下:

图的数据结构与前一个算法相同,采用的还是邻接矩阵。
先将当前位置结点设置为已访问,然后根据当前的结点位置,计算下一步还能走哪些位置,并把这些位置放入到一个集合ArrayList中,每走一步,step+1。
遍历ArrayList中存放的所有位置,看看哪个可以走通,如果走通就继续,走不通就回溯。
最后判断是否完成了任务:使用step和应该走的步数比较,如果没有达到数量,则表示没有完成任务,将整个结果置0。

注意这样的搜索结果会根据策略的不同而改变,不同的策略执行的时间快慢也不一样,在这里,我们可以通过贪心算法对它进行优化,具体过程如下

在马踏棋盘算法获取下一步可以走的位置集合ArrayList之前,我们需要对ArrayList集合中点的下一步的所有集合的数目进行非递减排序
这样在ArrayList中第一个结点就是下一步应该走的结点,我们需要优先选择它,因为它的后续结点最少,代表着需要回溯的点也越少。

采用了贪心算法优化之后,程序执行的时间效率会大大提高。


三、逻辑设计

程序有三个包分别为:domain、service、 ui
domain包下提供了两个类:

  • View类是景点的抽象,生成的对象代表学校里的景点,具有私有属性:景点的编号、名称以及景点的介绍。
  • MGraph类是图的数据结构,采用邻接矩阵表示,顶点数组中存放每一个景点的对象,该类的构造方法初始化了图的结点和边。

Service包下提供了三个类:

  • ShortestPathService类提供了求图中任意两个景点之间的最短路径的Floyd算法。
  • TourPathService类提供了求推荐游览路径的马踏棋盘算法。
  • ViewsService类用来展示各景点的详细信息。

ui包中是Swing的一些组件类,用于实现GUI,同时其中的MainInterface类也是程序的入口。

以下是程序的流程图:
数据结构课设可以做什么,数据结构,算法,图论


四、物理设计

本实验的数据结构采用图的邻接矩阵各算法也依据邻接矩阵来实现。图中每个结点都是一个景点View类的对象。
下图是景点的带权无向图:
数据结构课设可以做什么,数据结构,算法,图论

以下是图以及景点类的数据结构:

package com.domain;


import java.util.Arrays;

/*
    类MGraph:用于表示学校景点的无向网
*/
public class MGraph {
    //最大顶点数
    public static final int MAX_SIZE = 20;
    //最大权值,即∞
    public static final int MAX_INT = 65535;
    //顶点数组
    private View[] vertex = new View[MAX_SIZE];
    //图的邻接矩阵
    private int[][] adj = new int[MAX_SIZE][MAX_SIZE];
    //图的前趋结点数组
    private int[][] pre = new int[MAX_SIZE][MAX_SIZE];
    //图的顶点数和边数
    private int vertexNum, edgeNum;


    //初始化图结构
    public MGraph() {
        //设置结点数与边数
        vertexNum = 12;
        edgeNum = 17;
        //初始化顶点数组
        initialVertex(vertex);
        //初始化邻接矩阵
        initialAdj(adj);
        //初始化前趋结点数组
        initializePre(pre);
    }


    //初始化顶点数组
    private void initialVertex(View[] vertex) {
        vertex[0] = new View(1, "行政楼", "办公主楼,校领导办公的地方~");
        vertex[1] = new View(2, "海韵湖", "海韵湖连通着长江,景色优美,是饭后散步的好地方,外围有红蓝塑胶跑道,学校时常举办环湖跑比赛");
        vertex[2] = new View(3, "图书馆", "图书馆总共五层,室内环境优雅,藏书众多,更有窗边观湖雅座,是各大卷王的必争之地");
        vertex[3] = new View(4, "东食堂", "东食堂有很多特色菜肴,食堂对面就是图书馆");
        vertex[4] = new View(5, "东操场", "体育锻炼的好地方,时常举办足球比赛");
        vertex[5] = new View(6, "南门", "校门庄严气派,毗邻长晖路,马路对面有烧烤和麻辣烫卖");
        vertex[6] = new View(7, "文体中心", "一楼有乒乓球馆、健美操馆、健身房,二楼有室内篮球场和羽毛球场,是锻炼身体的好去处,旁边还有船苑剧场可以看电影");
        vertex[7] = new View(8, "西操场", "平时举办运动会的地方");
        vertex[8] = new View(9, "经世楼", "学校四座教学楼中的一座,其它几个分别为笃学楼、明德楼以及文理大楼,教师多媒体讲台、多功能显示屏、打印机、自动贩卖机等基础设施完善");
        vertex[9] = new View(10, "文理大楼", "长山校区的地标建筑,共21层,到天台可以俯瞰整个校园景色,气势磅礴");
        vertex[10] = new View(11, "西食堂", "西食堂有三层,第三层是民族食堂,可以品尝各地的特色菜肴");
        vertex[11] = new View(12, "西宿舍区", "西片区学生住宿的地方,分为7个组团,从宿舍到教学楼要跑好多路QAQ");
    }

    //初始化邻接矩阵
    private void initialAdj(int[][] adj){
        //先初始化
        for (int i = 0; i<vertexNum;i++){
            for (int j = 0; j<vertexNum;j++){
                adj[i][j] = MAX_INT;
            }
            adj[i][i] = 0;
        }
        adj[0][1]=300;      //行政楼-海韵湖
        adj[1][0]=300;
        adj[0][9]=700;      //行政楼-文理大楼
        adj[9][0]=700;
        adj[9][8]=100;      //文理大楼-经世楼
        adj[8][9]=100;
        adj[2][9]=400;      //文理大楼-图书馆
        adj[9][2]=400;
        adj[1][2]=600;      //海韵湖-图书馆
        adj[2][1]=600;
        adj[7][8]=100;      //西操场-经世楼
        adj[8][7]=100;
        adj[2][7]=550;      //西操场-图书馆
        adj[7][2]=550;
        adj[7][10]=250;     //西食堂-西操场
        adj[10][7]=250;
        adj[6][7]=100;      //文体中心-西操场
        adj[7][6]=100;
        adj[2][3]=100;      //图书馆-东食堂
        adj[3][2]=100;
        adj[6][10]=300;     //西食堂-文体中心
        adj[10][6]=300;
        adj[3][6]=550;      //文体中心-东食堂
        adj[6][3]=550;
        adj[10][11]=200;        //西宿舍区-西食堂
        adj[11][10]=200;
        adj[5][6]=250;      //文体中心-南门
        adj[6][5]=250;
        adj[3][4]=100;      //东食堂-东操场
        adj[4][3]=100;
        adj[5][11]=700;     //西宿舍区-南门
        adj[11][5]=700;
        adj[4][5]=250;      //南门-东操场
        adj[5][4]=250;
    }

    //初始化前趋结点数组
    private void initializePre(int[][] pre){
        for (int i = 0; i<vertexNum;i++){
            Arrays.fill(pre[i],i);
        }
    }

    public View[] getVertex() {
        return vertex;
    }

    public void setVertex(View[] vertex) {
        this.vertex = vertex;
    }

    public int[][] getAdj() {
        return adj;
    }

    public void setAdj(int[][] adj) {
        this.adj = adj;
    }

    public int getVertexNum() {
        return vertexNum;
    }

    public void setVertexNum(int vertexNum) {
        this.vertexNum = vertexNum;
    }

    public int getEdgeNum() {
        return edgeNum;
    }

    public void setEdgeNum(int edgeNum) {
        this.edgeNum = edgeNum;
    }

    public int[][] getPre() {
        return pre;
    }

    public void setPre(int[][] pre) {
        this.pre = pre;
    }
}

package com.domain;
/*
    类View:用于表示每一个景点
*/
public class View {
    //景点的编号
    private int id;
    //景点的名称
    private String name;
    //景点的介绍
    private String introduction;

    public View(int id, String name, String introduction) {
        this.id = id;
        this.name = name;
        this.introduction = introduction;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getIntroduction() {
        return introduction;
    }

    public void setIntroduction(String introduction) {
        this.introduction = introduction;
    }
}

下面是最短路径Floyd算法的代码:

//Floyd算法
    private void floyd() {
        //变量保存距离
        int len = 0;
        //对中间结点遍历,k就是中间结点的下标
        for (int k = 0; k < mGraph.getVertexNum(); k++) {
            //从i结点开始出发
            for (int i = 0; i < mGraph.getVertexNum(); i++) {
                //到达j结点
                for (int j = 0; j < mGraph.getVertexNum(); j++) {
                    //从i结点出发,经过中间结点k,到达j结点的距离
                    len = dis[i][k] + dis[k][j];
                    //如果比原来的距离小,更新距离和前趋结点
                    if (len < dis[i][j]) {
                        dis[i][j] = len;
                        pre[i][j] = pre[k][j];
                    }
                }
            }
        }
    }

下面是推荐游览路径马踏棋盘算法及其使用贪心算法优化的代码:

 /*
        DFS寻找哈密尔顿路径:马踏棋盘算法
        result为图,id为当前点(从0开始),step为步数记录,初始步数为1
    */
    private void traversalMap(int[] result, int id, int step){
        //更新结果图
        result[id] = step;
        //标志该位置已经访问
        visited[id] = true;
        //获取当前位置可以走的下一个位置的集合
        ArrayList<Integer> ps = next(id);
        //利用贪心算法排序优化,优先选择下一步可选择位置最少的点
        sort(ps);
        //遍历ps,递归回溯
        while (!ps.isEmpty()){
            //取出下一个可以走的位置
            Integer p = ps.remove(0);
            //判断该点是否被访问过
            if (!visited[p]){
                //如果没有访问过,进行下一步
                traversalMap(result,p,step+1);
            }
        }
        //判读是否遍历了所有的点,使用step和应该走的步数比较,如果没有到达数量,将整个结果置0
        //step<结点数 成立的情况有两种
        //1.所有结点到目前为止仍然没有走完
        //2.所有结点到目前为止已经走完,处于回溯过程(无路可走)
        if (step<mGraph.getVertexNum() && !finished){
            result[id] = 0;
            visited[id] = false;
        }else {
            //如果完成了
            finished = true;
        }
    }
    
	//根据当前点的位置,计算还能走哪些位置,把这些点的id放入一个ArrayList中,id从0-11
    private ArrayList<Integer> next(int id) {
        ArrayList<Integer> ps = new ArrayList<>();
        for (int j = 0; j<mGraph.getVertexNum(); j++) {
            //如果这条路连通,就把点加入
            if (dis[id][j]<MGraph.MAX_INT){
                ps.add(j);
            }
        }
        return ps;
    }

    //利用贪心算法对DFS优化
    //根据当前这一步的下一步的选择位置,进行非递减排序,减少在DFS时的回溯次数
    private void sort(ArrayList<Integer> ps){
        ps.sort(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return next(o1).size()-next(o2).size();
            }
        });
    }

查询景点详细信息的代码最为简单,但用GUI实现景点的展示对我这个新手来说还是很繁琐的。

//传入景点id,返回景点的介绍(字符串)
    public String getViewInformation(int id){
        return vertex[id-1].getIntroduction();
    }

总结

对于本次实验来说还有许多可以改进的地方文章来源地址https://www.toymoban.com/news/detail-787466.html

  1. 图的结点是不可以修改的,其实一开始也考虑过通过文件读取图中结点以及边的权值信息,或者用户可以手动修改结点和边的信息。但因为想要用GUI展示,对于结点的修改肯定要动态的改变地图样貌,这样一来实现起来就非常困难,而且用户对结点修改的步骤也较为繁琐,所以索性就把结点和边定死了。
  2. 图不能动态的展示,每次查询最短路径只能通过文字信息展现,不能在地图上画出此次查询的最短路线。因为要实现这一功能需要加上窗口的坐标变换和计算,画出相应的行动轨迹,对我来说过于困难。
  3. 功能较少,只有查询景点、最短路径和推荐路径这三个功能。其实一方面可以根据路况信息、甚至是地形的坡度来动态的改变边的权值。另一方面可以增加每个景点的推荐程度这一信息来对景点进行排序,给用户优先级的推荐等。
  4. 推荐路径只能推荐从当前结点出发一个可行的哈密尔顿道路,并不能求出游览所有景点一次的最短道路。

到了这里,关于数据结构课程设计——项目2:校园导游咨询的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构课程设计

    编制一个能演示执行集合的交、并和差运算的程序。 要求: 集合元素用小写英文字母,执行各种操作应以对话方式执行。 算法要点:利用单链表表示集合;理解好三种运算的含义 分析 : 输入:输入应该具有判断是否为小写字母的功能,如果不是小写字母,应该舍去,同时

    2024年02月02日
    浏览(47)
  • 【数据结构课程设计】关键路径问题

    1 问题描述与功能需求分析 1.1问题描述 1) 任务:设计一个程序求出完成整项工程至少需要多少时间以及整项工程中的关键活动。 2)基本要求: (1)对一个描述工程的 AOE 网,应判断其是否能够顺利进行。 (2)若该工程能顺利进行,输出完成整项工程至少需要多少时间,以及

    2024年02月10日
    浏览(44)
  • 数据结构课程设计1: 区块链

    1.任务: [问题描述] 使用链表设计一个保存信息的系统,该系统拥有类似区块链的设计以防止信息被轻易篡改。 该题目使用一个链表。信息保存在链表的每一个节点中,每个节点需要包含该节点的编号、信息和校验码。其中: + 每个节点的编号按照顺序递增,从0开始。 + 节

    2023年04月16日
    浏览(113)
  • 数据结构课程设计 ——考试报名系统

    数据结构课程设计 ——考试报名系统 一、项目功能要求 完成对考生信息的建立,查找,插入,修改,删除等功能。其中考生信息包括准考证号,姓名,性别,年龄和报考类别等信息。项目在设计时应首先确定系统的数据结构,定义类的成员变量和成员函数;然后实现各成员

    2024年02月04日
    浏览(49)
  • 数据结构课程设计 仓储管理系统

    【基本功能】 把货品信息表抽象成一个线性表,货品信息(包括ID、货品名、定价、数量等)作为线性表的一个元素,实现:按ID、货品名分别查找某货品信息(包括ID、货品名、定价、数量等);收录货品(如果货品在帐中已有,则只将总库存量增加。否则插入新增信息);

    2024年01月23日
    浏览(65)
  • 一、课程设计目的与任务《数据结构》课程设计是为训练学生的数据组织能力和提高程序设计能力而设置的增强实践能力的课程。目的:学习数据结构课程,旨在使学生学会分析研究数据对象的特性,学会数据的组织方法,以

    一、课程设计目的与任务 《数据结构》课程设计是为训练学生的数据组织能力和提高程序设计能力而设置的增强实践能力的课程。目的:学习数据结构课程,旨在使学生学会分析研究数据对象的特性,学会数据的组织方法,以便选择合适的数据的逻辑结构和存储结构以及相应

    2024年02月21日
    浏览(66)
  • 【数据结构课程设计】简单搜索引擎系统

    该程序使用python语言实现利用爬虫代码爬取网站链接信息,将网站中文词语通过结巴分词进行分割,并存储爬取的数据信息,利用结巴分词库处理输入框用户输入的词语,进行搜索,通过链接评价函数,优先显示评分较高的链接;设计简单的html页面,实现可视化搜索功能。

    2024年01月23日
    浏览(57)
  • 《数据结构与算法分析》课程设计——迷宫问题

    中国矿业大学信控学院   补一下我之前在博客园发布的内容  懒得调了, 想复制完整代码直接复制最下面的 ,想复制分布代码去看我博客园链接吧 《数据结构与算法分析》课程设计——迷宫问题 - 刷子zz - 博客园 一、  问题描述 问题中迷宫可用方阵[m,n]表示,0表示能通过

    2024年02月10日
    浏览(48)
  • 数据结构课程设计:学生成绩管理系统

    目  录 第一章   需求分析 第二章 概要设计 第三章 详细设计 第四章 测试报告 第五章 安装及使用 第六章 项目总结 第七章 源码 一.需求分析        学生成绩管理是一个学校不可缺少的部分,它的内容对于学校的管理者和学生以及学生家长来说都至关重要,所以一个良好

    2024年02月02日
    浏览(66)
  • 数据结构课程设计——哈夫曼编/译码系统设计与实现(C++)

    对于生产实际的问题,本设计可以作为一个无损数据压缩工具,在需要传输海量数据时,利用哈夫曼编码可以将数据进行压缩,从而减小传输的数据量,提高数据传输效率。同时,哈夫曼编码也可以应用于数据加密和解密等领域。 本设计的主要目的是学习哈夫曼编码算法,并

    2024年02月04日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包