很多老师反映教软件工程和程序设计的时候没有合适的题目,《构建之法》提供了下面的题目,都是从简单的解题思路入手,逐步增量改进。学生们可以复习基本的编程技能,然后逐步加入模块化,文件处理,单元测试,信息隐藏,面向对象的分析,MVC 等概念和实践。 大家可以选用:
- 四则运算练习
- 计算程序文件的行数,及其扩展问题
- 电梯调度
下面的题目, 从简单的数据结构开始,让同学们逐步练习。
0. 请上网搜到最新的北京地线路图。
1. 把这个图的各个线路,各个站点,换乘信息等用文本文件 (假设名字叫 beijing-subway.txt)的形式保存起来,应该保存的信息有 {线路号,线路的各个站名,车站的换乘信息}, 应用程序可以读取这个文件,就能掌握关于北京地铁线路的所有信息,应该用什么样的格式呢? 在我们生活中,我们用自然语言,或者图表来表示信息, 当一个有足够生活经历的成年人看到上面的线图路,她马上可以理解 “两个小白圆点中间有一条线表示这两个车站是相邻的”。 当你要让电脑程序来处理这些信息,但是程序只知道一行,一个字,一个字节地处理信息, 怎么办,怎么表示 “这个车站可以转 5 号线”?
2. 写一个命令行程序 (不妨叫 subway.exe),这个程序启动的时候, 会读取beijing-subway.txt 的信息,然后这个程序就等待用户的输入, 用户可以输入地铁的线路编号,然后程序就输出此地铁线路的所有站名(按某一方向顺序输出即可)。 输出站名后,程序又进入等待状态。
3. 能否进一步, 找到两点之间的最有效线路? 请实现下面这个需求:
subway.exe /b 知春路 中关村
返回经历的站名的个数,和路径,如果有换乘,请列出换乘的线路, 例如:
4
知春路
知春里
海淀黄庄 换乘10号线
中关村
3.1 抽象
在我们做测试的过程中,我们可以比较具体的车站的名字,已验证算法的正确性, 但是我们实际上并不在乎这个具体名字是 "知春路", 还是 "惠新西街南口",我们只要知道它们相同就好了。 能否给每个车站一个数字的标识,这样便于比较? 请修改你的 beijing-subway.txt 地图文件,把车站的唯一标识ID 加上,然后再修改程序中读取文件的部分,让它能处理ID,而不是仅仅车站名字。修改程序之后,请保证程序依然能够完成它原有的功能。
4. 既然有了地图和 “返回两个站点之间最短路径” 的功能, 我们怎么知道程序员实现的这个功能是正确的呢? 我们可以抽样调查,但是不能确保。能否测试这个模块呢? 这个模块可能是程序中的一个类,或几个相关的类,我们可以通过给它写单元测试,或模块测试的办法。
请把subway 程序中 “返回两个站点之间最短路径” 的功能独立出来,成为一个DLL,或者一个类,那么我们就可以用《构建之法》 提到的单元测试, 或者 四则运算练习题 提到的测试模块的方法测试了。
请把这个exe 分解为几个独立的模块,然后用你所在的平台的单元测试工具来测试。
5. 如果乘客有钱又有闲,那么,怎样才能尽可能快地遍历地铁的所有车站呢(只用经过一次,不用下车,就算经过车站)。 例如,注意到13号线 和 10 号线相交的知春路地铁站,我们选它作为一个起始站,从这个站出发,要经历多少站(换乘不出地铁系统,即不能从一个地铁口走到路面,然后从另一个站进去),才能把所有地铁站都遍历呢?
扩展命令行程序,让它接受一个地铁站名。 例如这个格式: subway.exe /a 知春路
程序输出总共经历多少站, 以及经历的站名, 举一个特例,假如地铁系统只有知春路, 西土城两个站, 那么这个程序应该输出:
3
知春路
西土城
知春路
5.1 从现实生活中我们知道,在地铁系统中换乘是比较麻烦的一件事情,花费额外的时间和体力 (下车,步行到下一个线路,等车,挤上车,再找座位),我们上一个遍历算法没有考虑到这一点,有点不接地气。 如果我们做一个改进, 每次换乘,相当于额外经历了 3 个车站, 我们还是要求遍历所有车站的最优线路,我们的程序应该怎么修改呢? 总的车站数量 = 实际经过的车站数量 + 换乘等价的车站数量
我们在前面几步的修改中, 把数据格式,程序的功能,程序的结构都稍稍修改了一些,但是整体程序还能按原来的需求运行。 希望初学者在每一步都只改一个方面,修改之后,能测试程序,保证没有引入其它错误。 有基础的同学可以用源代码管理工具来管理各个版本的代码。
5.2 既然有程序能输出解答, 那么我们怎么验证呢? 睁大眼睛一个一个地数么? 我们不是会写程序么? 来一个:
subway.exe /z filename
filename 指向一个文本文件,里面放了 /a 参数的答案 (就是题目 3 的输出, 一个数字加上站名)
这个 /z 参数要求在命令行输出
true: 如果filename 文件中的数据的确覆盖了整个地铁的所有站点至少一次,并且车站的数量是对的,车站的遍历次序是合理的。
false: 车站的遍历次序仍然合理,但是有遗漏的站点,或者车站的数量错误。 如果有遗漏的站点,这个程序要至少输出一个遗漏的车站名。
error: 如果车站的遍历次序不合理(例如直接从“知春路” 站到了“中关村” 站), 打印出出错的两个站名。
6. 我们前面的练习都是基于命令行的,能否做成图形界面呢? 首先我们要给每个站点一个坐标信息。
1)请修改 beijing-subway.txt 文件,加入适当的信息,为实现图形界面做准备。 你要如何设计这些坐标呢?
2)请改进 subway.exe, 加一个 /g 的命令行参数, 让它根据你提供的坐标画出各个地铁站,线路,以及换乘站。
我们看到,所有要展现的信息都要存储起来,存储还要有一定的规则,这样程序才好正确地,高效地读出来。 存储有下面三个方案:
a) 用文本文件, 用自定义的格式存放
b) 用XML 格式存放
c) 还可以用数据库的方式来存放, 例如 sqlite
d) 还可以用自己定义的二进制的格式来存放。
请比较几种方式的优缺点,特别是,这些方式如何应对变化的内部,外部因素。 例如,在 d) 方案中, 如果要增加一个地铁站,或者修改一个地铁站的名字,我们应该怎么做呢?
7. 现在我们回过头来,把遍历的解法搬到GUI (图形界面)来。
1)扩展 subway.exe, 处理下面参数的时候,
subway.exe /g 知春路
程序在图形界面中显示地铁地图 (各个站点的相对位置和官方地图类似即可),然后用一个小亮点表示乘客,乘客正在经过的车站就会闪亮,乘客走过的路用不同的颜色标识,同时在适当的地方有数字表明乘客已经经过车站的数目。
8. 前面几步都做好了,下面就是工程问题了:
8.1 请让程序能处理上海的地铁地图,或者其它城市的地图。把程序由 “固定处理一个地图” 升级为 “能处理多个地图”, 程序的什么模块需要变化?
8.2 请把程序移植到网页/手机,用户指定起点和终点,程序就报告这两个点的最优路径。 把程序从 PC 平台搬到 Web 或 Mobile, 原来写的所有代码都要扔掉么? 还是有很多部分可以重用? 怎样重用?