1、1,数据结构课程设计王晓琳 (提交设计报告和源程序邮箱),2,巩固和加深对数据结构基本知识的理解,提高综合运用课程知识的能力。 掌握解决复杂问题的程序设计方法和技术学会数据的组织方法和现实世界问题在计算机内部的表示方法,并针对问题的应用背景分析,选择最佳的数据结构与算法。 提高自学参考书籍,查阅手册和文献资料的能力。 培养文档组织、书写能力。,课程设计目标,3,线性结构 树形结构(层次结构) 图(网)结构结构: 逻辑结构 存储结构 算法,数据结构内容回顾,开发语言和环境,C+ Eclipse 或 VC+ Java Eclipse,4,5,1.完成软件设计开发,运行得到正确的结果 界面设计:可
2、输入、输出,操作简单清晰 功能设计:尽可能满足实际运行要求。有健壮性2撰写课程设计报告,设计要求,6,设计报告 可运行源代码 邮件标题:数据结构课程设计-课程设计题目-10-班-学号-姓名 设计报告命名格式:数据结构课程设计-课程设计题目-10-班-学号-姓名.doc 源代码打包命名格式:课程设计题目-10-班-学号-姓名.rar,课程设计提交,7,课程设计题目 姓名、学号、班级 日期 设计要求 问题描述(介绍题目内容) 输入要求 输入形式 输入数据例子 输出要求 输出形式 输出数据例子,课程设计报告要求,8,2.数据结构与算法描述 解决问题的整体思路 描述解决该问题所需要的数据结构与算法 处
3、理问题用到的关键数据结构和算法都要描述,不要只描述主函数 数据结构和算法可用伪码和图示描述,不要只写源代码和注释 类的定义和类之间的关系,可用类图等形式来描述。,课程设计报告要求,9,3.测试结果 测试输入 测试输出 测试中的问题及解决 注: 测试输入及对应的测试输出可放入一张表格中 有充分的测试数据,必须包括容错测试数据,课程设计报告要求,10,4.分析与探讨 测试结果分析 算法复杂性分析 探讨更多解决问题的途径,或者提出自己的见解,改进算法以得到更好结果的建议。,课程设计报告要求,11,附录:实现源代码 程序风格清晰易理解 有充分的注释,有意义的注释少于代码的30%将不得分。课程设计必须独
4、立完成,课程设计报告有雷同的将不得分。 必须在指定的时间内上交课程设计报告。,课程设计报告要求,12,课程设计题目,13,输入: 不含变量的数学表达式的中缀形式,可以接受的操作符包括+、-、*、/、%和(、)。 输出: 如果表达式正确,则输出表达式的结果,如果表达式非法,则输出错误信息。 注: 输入/输出形式可采取终端设备输入/输出,也可采用文件输入/输出,一个文件中可包含多个表达式 知识点:堆栈、队列,1、计算器,14,输入:文本文件(压缩文件) 输出:压缩文件(文本文件) (压缩率)知识点:堆、霍夫曼树、二叉树遍历备注:文本文件为一篇英文文章(汉字文件),2、文本文件压缩,15,用无向网表
5、示校园景点平面图,图中顶点表示主要景点,存放景点的编号、名称、简介等信息,图中的边表示景点间的道路,存放路径长度等信息。要求能够回答有关景点介绍、游览路径等问题。 要求 (1) 查询任意景点的相关信息; (2) 查询图中任意两个景点间的最短路径。 (3) 查询图中任意两个景点间的所有路径。 (4) 增加、删除、更新有关景点和道路的信息。 (5)* 求多个景点的最佳(最短)游览路径。 知识点:单源点最短路径、任意顶点间的最短路径、图的搜索,3. 校园导游,16,给定一个计算机网络以及机器间的双向连线列表,每一条连线与允许两端的计算机进行直接的文件传输,其他计算机间若存在一条连通路径,也可以进行间
6、接的文件传输。 要求: 任意指定两台计算机,判断它们之间是否可以进行文件传输? 判断整个网络中是否任意两台机器间都可以文件传输?若不可以,请给出当前网络中连通分量的个数 增加两台计算机之间的连线。 知识点:Union-find问题,4、检查网络,迷宫老鼠(rat in a maze)问题要求寻找一条从入口到出口的路径。,栈的应用例:迷宫老鼠,17,输入:迷宫 输出:从入口到出口的路径 路径是由一组位置构成的,每个位置上都没有障碍,且每个位置(第一个除外)都是前一个位置的东、南、西或北的邻居。,问题描述,18,假定用nm的矩阵来描述迷宫,位置(1,1)表示入口,(n,m)表示出口,n和m分别代表
7、迷宫的行数和列数。 迷宫中的每个位置都可用其行号和列号来指定。在矩阵中,当且仅当在位置(i,j)处有一个障碍时其值为1,否则其值为0。,迷宫的描述,19,迷宫的描述,20,程序主要功能模块 输入迷宫、寻找路径和路径输出 开始显示欢迎界面,设计方案,21,输入迷宫:确定输入方式及输入界面 用户按逐行方式输入矩阵 在输入矩阵数据之前,用户必须首先给出矩阵的行数(它同时也是矩阵的列数),设计方案,22,用户输入提示,设计方案,考虑:颜色的使用、声音的使用、信息的询问、输入数据的验证等等,23,首先把迷宫的入口作为当前位置。 如果当前位置是迷宫出口,那么已经找到了一条路径,搜索工作结束。 如果当前位置
8、不是迷宫出口,则在当前位置上放置障碍物,以便阻止搜索过程又绕回到这个位置。 然后检查相邻的位置中是否有空闲的(即没有障碍物),如果有,就移动到这个新的相邻位置上,然后从这个位置开始搜索通往出口的路径。如果不成功,选择另一个相邻的空闲位置,并从它开始搜索通往出口的路径。为了方便移动,在进入新的相邻位置之前,把当前位置保存在一个堆栈中。 如果所有相邻的空闲位置都已经被探索过,并且未能找到路径,则表明在迷宫中不存在从入口到出口的路径。,寻找路径实现思路,24,对于迷宫内部的位置(非边界位置),有四种可能的移动方向:右、下、左和上。 对于迷宫的边界位置,只有两种或三种可能的移动。 为了避免在处理内部位
9、置和边界位置时存在差别,可以在迷宫的周围增加一圈障碍物。,简化算法的处理,25,迷宫的描述,增加一圈障碍物,26,可以用行号和列号来指定每个迷宫位置,行号和列号被分别称之为迷宫位置的行坐标和列坐标。 可以定义一个相应的类Position来表示迷宫位置,它有两个私有成员row和col。 为保存从入口到当前位置的路径,可以采用以下基于公式化描述的堆栈: Stack path(MaxPathLength); 其中MaxPathLength是指最大可能的路径长度(从入口到迷宫中任一位置)。,位置表示,27,寻找路径算法,bool FindPath() / 寻找从位置( 1 , 1 )到出口( m ,
10、m )的路径 增加一圈障碍物; / 对跟踪当前位置的变量进行初始化 Position here; here.row = 1; here.col = 1; maze 1 1 = 1; / 阻止返回入口,28,/ /寻找通往出口的路径 while (here不是出口) do 选择here的一个可行的相邻位置;if (存在这样一个相邻位置neighbor) 把当前位置here 放入堆栈path ;/ 移动到相邻位置,并在当前位置放上障碍物here = neighbor;mazehere.row here.col = 1;else / 不能继续移动,需回溯if (堆栈path为空) return fa
11、lse;回溯到path栈顶中的位置here; return true; ,29,按一种固定的方式来选择可行的相邻位置,将可以使问题得到简化。 例如,可以首先尝试向右移动,然后是向下,向左,最后是向上,对应的移动编号依次为0,1,2,3。 从当前位置here沿移动方向i(编号)移动到下一个相邻位置时,则row和col坐标的增量是offseti.row, offseti.col.,下一个移动位置的选择,30,下一个移动方向的计算,从here回退到前一个位置(next)后下一个移动方向的计算 if (next.row=here.row) /here为next邻居option=2+next.col-h
12、ere.col;else option =3+next.row-here.row;,31,假定maze、m (迷宫的大小)和path都是按如下方式定义的全局变量: int *maze, m; Stack *path;,迷宫算法实现,32,bool FindPath() / 寻找从位置(1,1)到出口(m,m)的路径/如果成功则返回true ,否则返回false / 如果内存不足则引发异常NoMem path = new Stack(m * m - 1); /对偏移量进行初始化 Position offset4; offset0.row = 0; offset0.col = 1; /向右 off
13、setl.row = 1; offsetl.col = 0; / 向下 offset2.row = 0; offset2.col = -1; /向左 offset3.row = -1; offset3.col = 0; /向上,搜索迷宫路径的代码,33,/在迷宫周围增加一圈障碍物 for (int i=0; i=m+l; i+) maze0i= mazem+li=1; /底和顶mazei0= mazeim+l=1; /左和右 Position here; here.row = 1; here.col = 1; mazeii= 1; / 阻止返回入口 int option = 0; /下一个移动
14、方向编号 int LastOption = 3;,搜索迷宫路径的代码,34,/寻找一条路径 while (here.row!=m|here.col!=m)/ 不是出口/寻找并移动到一个相邻位置int r, c;while (option = LastOption) r = here.row + offsetoption.row;c = here.col + offsetoption.col;if (mazerc= 0) break; /可行的相邻位置option+; /下一个选择,搜索迷宫路径的代码,35,/ 找到一个相邻位置了吗? if (optionAdd(here) ;here.row
15、= r; here.col = c;/设置障碍物以阻止再次访问mazerc= 1;option = 0; ,搜索迷宫路径的代码,36,else /没有可用的相邻位置,回溯if (path-IsEmpty() return false;Position next;path-Delete(next) ; if (next.row = here.row) /here为next邻居option = 2 + next.col - here.col;else option = 3 + next.row - here.row;here = next; return true;/到达迷宫出口 ,搜索迷宫路径的
16、代码,37,思考,迷宫自动生成?寻找从入口到出口的最短路径?,38,队列的应用电路布线,39,电路布线问题,40,在解决电路布线问题时,一种很常用的方法就是在布线区域叠上一个网格,该网格把布线区域划分成nm个方格,就像迷宫一样。 从一个方格a的中心点连接到另一个方格b的中心点时,转弯处必须采用直角。如果已经有某条线路经过一个方格,则封锁该方格。我们希望使用a和b之间的最短路径来作为布线的路径,以便减少信号的延迟。,电路布线算法思想-1,1. 标识网格,41,先从位置a 开始搜索,把a 可到达的相邻方格都标记为1(表示与a相距为1),然后把标号为1的方格可到达的相邻方格都标记为2(表示与a相距为
17、2),继续进行下去,直到到达b或者找不到可到达的相邻方格为止。,电路布线算法思想-2,2. 构造最短路径,42,为了得到a与b之间的最短路径,从b开始,首先移动到一个比b的编号小的相邻位置上。一定存在这样的相邻位置,因为任一个方格上的标号与它相邻方格上的标号都至少相差1。 接下来,从当前位置开始,继续移动到比当前标号小1的相邻位置上。 重复这个过程,直至到达a为止。,电路布线算法思想-3,2.构造最短路径,43,电路布线数据结构,一个m x m 网格被描述成一个二维数组0 -空白的位置1 -被阻塞的位置 整个网格被包围在一堵由1构成的“墙”中。 数组 offsets帮助我们从一个位置移动到其相
18、邻位置。 一个链表队列用来跟踪这样的方格:该方格本身已被编号,而它的相邻位置尚未被编号。,44,电路布线算法-1,bool FindPath(Position start, Position finish, int/因为数组中采用0和1来表示空白位置和封锁位置,45,电路布线算法-2,/ 标记网格 do /标记当前位置here的相邻位置for (int i=0; i相邻位置数; i+)选择here的下一个的相邻位置nbr;if (nbr是空白位置)标记nbr的编号为here的编号+1;if(nbr是finish) break; 将位置nbr入队列Q; if(nbr是finish) break;
19、if (队列Q为空) return false;here从队列中取出一个相邻位置未被标记的位置,46,电路布线算法-3,/构造路径 路径长度PathLen=finish的编号-2; path=new PositionPathLen;/当前位置回溯至finish here=finish; for(int j=PathLen-1;j=0;j-)pathj=here;寻找比here编号小1的位置nbr/移动到前一个位置here=nbr;Return true; ,47,48,bool FindPath(Position start, Position finish, int/左和右,寻找电路布线最短
20、路径实现代码-1,49,/初始化offset Position offset4; offset0.row=0; offset0.col=1; /右 offset1.row=1; offset1.col=0; /下 offset2.row=0; offset2.col=-1; /左 offset3.row=-1; offset3.col=0; /上 int NumOfNbrs=4; /一个网格位置的相邻位置数 Position here, nbr; here.row=start.row; here.col=start.col; gridstart.rowstart.col=2; /封锁,/在起始
21、位置上标记2,,寻找电路布线最短路径实现代码-2,50,/ 标记可到达的网格位置 LinkedQueue Q; do /标记相邻位置for (int i=0; iNumOfNbrs; i+) nbr.row=here.row+offseti.row;nbr.col=here.col+offseti.col;if (gridnbr.rownbr.col=0) /新位置gridnbr.rownbr.col=gridhere.rowhere.col+1;if(nbr.row=finish.row) /if结束 /for结束,寻找电路布线最短路径实现代码-3,51,/已到达finish吗?if(nbr
22、.row=finish.row),寻找电路布线最短路径实现代码-4,52,/构造路径 PathLen=gridfinish.rowfinish.col-2; path=new PositionPathLen;/回溯至finish here=finish; for(int j=PathLen-1;j=0;j-)pathj=here;/寻找前一个位置for(int i=0;iNumOfNbrs;i+)nbr.row=here.row+offseti.row;nbr.col=here.col+offseti.col;if(gridnbr.rownbr.col=j+2) break;here=nbr;
23、/移动到前一个位置 Return true; ,寻找电路布线最短路径实现代码-5,队列的应用识别图元,问题: 数字化图像是一个mm 的像素矩阵。 在单色图像中,每个像素的值要么为0,要么为1,值为0的像素表示图像的背景,而值为1的像素则表示图元上的一个点,我们称其为图元像素。 识别图元就是对图元像素进行标记,当且仅当两个像素属于同一图元时,它们的标号相同。,53,识别图元示例,54,识别图元算法思路,通过逐行扫描像素来识别图元。 当遇到一个没有标号的图元像素时,就给它指定一个图元编号(使用数字2,3,作为图元编号),该像素就成为一个新图元的种子。 通过识别和标记与种子相邻的所有图元像素,可以确
24、定图元中的其他像素。我们把与种子相邻的像素称为1-间距像素。 接下来要识别和标记与1-间距像素相邻的所有无标记图元像素,这些像素被称为2-间距像素。 之后继续识别和标记与2-间距像素相邻的无标记图元像素。这个过程一直持续到再也找不到新的、相邻的无标记图元像素为止。,55,给定一个矩形布线区域,其外围有若干针脚。两个针脚之间通过布设一条金属线路而实现互连。这条线路被称为电线,被限制在矩形区域内。如果两条电线发生交叉,则会发生电流短路。所以,不允许电线间的交叉。每对互连的针脚被称为网组。 目标是要确定对于给定的网组,能否合理地布设电线以使其不发生交叉。,栈的应用开关盒布线,56,四个网组(1,4,
25、),(2,3),(5,6)和(7,8) 可布线开关盒(routable switch box),开关盒布线示例,四个网组(1 ,5),(2,3),( 4,7)和(6 ,8) 可布线开关盒?,57,当两个针脚互连时,其电线把布线区分成两个分区。 如果有一个网组,其两个针脚分别位于这两个不同的分区,那么这个网组是不可以布线的,因而整个电路也是不可布线的。 如果没有这样的网组,则可以继续判断每个独立的分区是不是可布线的。为此,可以从一个分区中取出一个网组,利用该网组把这个分区又分成两个子分区,如果任一个网组的两个针脚都分布在同一个子分区之中(即不会出现两个针脚分别位于两个子分区的情形),那么这个分区
26、就是可布线的。,策略,58,可以按顺时针或反时针方向沿着开关盒的外围进行遍历。 例:按顺时针方向从针脚1开始遍历,将依次检查针脚1, 2, ., 8。 针脚1和4属于同一个网组,那么在针脚1至针脚4之间出现的所有针脚构成了第一个分区,而在针脚4至针脚1之间未出现的所有针脚构成了第二个分区。 把针脚1放入堆栈,然后继续处理,直至遇到针脚4。这个过程使我们仅在处理完一个分区之后才能进入下一个分区。,方案,59,网组数据描述,对每个网组进行编号,并且每个针脚也得有一个对应的网组编号。 四个网组(1,4,),(2,3),(5,6)和(7,8) 输入数组net=1,2,2,1,3,3,4,4,60,开关
27、盒布线实现代码-1,bool CheckBox(int net , int n) / 确定开关盒是否可布线Stack *s = new Stack (n);/顺时针扫描各网组for (int i = 0; i IsEmpty() ) if (neti = nets-Top() ) /neti可布线,从堆栈中删除int x;s-Delete(x);) else s-Add(i); else s-Add(i);,61,开关盒布线实现代码-2,/ 是否有不可布线的网组? if (s-IsEmpty() delete s;cout“Switch box is routable“endl;return true; delete s; cout“Switch box is not routable“endl; return false; ,62,