在本文中,我们将会介绍针对一个问题提出计算机解决方案需要做哪些事。首先,我们可能需要用一到两个段落来做一下问题的描述。然后,从理解这个问题的描述到具体实现一个可行的计算机解决方案,这个过程称为解决问题。总而言之,我们希望在学习完本章内容之后,你将能够理解:
解决问题的方法有很多种。在本章,我们首先要研究的是一个3步走策略,即分析、设计、实现策略。
接下来,我们将通过一个“计算课程成绩”的示例来逐一示范这个3步走策略中的各个步骤,看看它们在解决问题过程中所发挥的作用,并以此开始这门课程的学习。
程序的开发通常始于针对某个问题的研究或分析。这是很显然的,如果我们想要确定一个程序要执行哪些操作,当然先得理解该程序要解决的问题。如果该问题已经完成了书面化描述,我们就可以从阅读这个问题开始进入分析步骤了。
在分析一个问题的过程中,做好对程序所需信息数据的命名工作会是很有帮助的。例如,我们可能会被要求计算出特定飞机在特定气象条件(比如温度、风向等)下,在指定机场跑道上可以成功起飞时的最大重量。这时,我们就可以在分析问题时将这项要计算的信息命名为maximumWeight,并将计算该信息所需的信息命名为temperature、windDirection等。
虽然这些数据并不代表整个解决方案,但是它们的确表述了问题的某个重要部分。这些数据名称会是我们编写程序以及在程序中进行计算工作时要用到的符号,比如可能我们要计算的是飞机在temperature的值为19.0时的maximumWeight。总而言之,这些数据通常都要经过各种形式的操作或处理之后,才能得到我们所期待的结果。在这其中,有些数据得从用户那里获取,也有些数据得经过一些相乘或相加的运算,还有些数据得在计算机屏幕上显示。
在某些时候,这些数据的值会被存储在计算机的内存中。当程序运行时,相同内存位置上的值是会变化的。另外,这些数据值通常都会有一个类型,比如整数类型、浮点数类型、字符串类型或其他各种存储类型。对于这种用于在程序运行时存储这些可变值的内存区块,我们称之为变量。
我们将会看到这些数据值施以某种特定行为意义的操作,这些特定的意义有助于我们将数据区分成由计算机显示的数据(输出),和计算出结果所需的数据(输入)。这些变量帮我们总结出了一个程序必须得做的事情。
通常情况下,我们都可以通过回答“给定输入能得到什么输出?”这个题目来更好地理解自己要解决的问题。因此,针对待解决的问题来进行举例往往是一个不错的思路。下面就是两个通过变量名的选择来精准描述其存储值的问题:
现在来总结一下,我们在分析问题过程中需要:
1.阅读并理解待解决问题的书面说明。
2.定义用来表示问题答案的数据,以作为输出。
3.定义用户为获取问题答案必须要键入的数据,以作为输入。
4.创建一些问题样例,以作汇总之用(就像上面做的那样)。
当然,教材中的问题有时会提供清楚的变量名,以及输入/输出时用到的值类型(比如字符串、整数、浮点数等)。如果没有的话,它们识别起来也往往是相对比较容易的。但在现实中,对于相当规模的问题来说,分析问题这个步骤通常是需要花费大量精力的。
自测题
1-1.请基于英镑与美元之间的汇率转换问题,分别为用来存储用户输入值以及程序输出值的变量赋予有意义的命名。
1-2.针对“从拥有200张CD的播放器中选取一张CD来播放”这个问题,请分别设定用来表示所有CD以及表示用户所选择的那张CD的变量名。
问题分析示例
问题:请根据右侧的课程成绩估算表,用作业项目、期中考试和期末考试这三项的加权值计算出这一门课的成绩。
如前所述,问题分析的工作要从理解问题的书面描述开始,然后确定解决该问题所需要的输入和输出。在这里,先定义并命名输出的内容是一个不错的切入点。因为,输出内容中通常存储的就是这个待解决问题的答案,它会驱使我们去深入理解这个待解决的问题。
一旦我们定义好了解决问题所需的数据,并赋予它们有意义的变量名之后,就可以将注意力转向如何完成任务了。就这个特定的问题而言,它要输出应该就是实际的课程成绩,我们将这个要输出给用户的信息命名为courseGrade。然后为了让这个问题更具有通用性,我们要让用户自己输入产生计算结果所需的值。毕竟如果这个程序可以要求用户提供所需的数据,那么它以后就可以用来计算多名学生任何一门课程的成绩了。在这里,我们将需要用户输入的这些数据命名为projects、midterm和finalExam。这样一来,我们目前就已经完成了问题分析这一步骤中的前3个动作:
1.理解待解决的问题。
2.定义要输出的信息:courseGrade。
3.定义要输入的数据:projects、midterm和finalExam。
接下来需要有一个问题样例,它有助于我们创建一个测试用例(test case),以验证输入的数据和程序产生的输出结果。例如,当projects为74.0、midterm为79.0、finalExam为84.0时,其平均加权值应该为78.0:
(0.50 × projects) + (0.20 × midterm) + (0.30 × finalExam)
(0.5 × 74.0) + (0.2 × 79.0) + (0.30 × 84.0)
37.0 + 15.8 + 25.2
78.0
到这里,问题的分析步骤就算完成了,我们确定了用于输入/输出的变量,这有助于我们了解计算机解决方案需要做哪些事,同时还获得了一个现成的测试用例。
自测题
1-3.请完成对下面问题的分析,这里你可能会需要用到一个准确的计算器。
问题:请基于某项投资的当前价值、投资期限(可能以年为单位)以及投资利率,估算出它的未来价值。在这里,投资利率和投资期限是步调一致的。也就是说,如果投资期限以年为单位,那么这里的投资利率就是年利率(例如8.5%,就是0.085);如果投资期限以月为单位,那么这里的投资利率就是月利率(例如,如果年利率是9%,那么月利率就是0.075)。其未来价值的计算公式如下:
future value = present value * (1 + rate)periods
设计这个概念背后所代表的是一系列动作,这其中包括为程序中的每个组件安排具有针对性的算法。而算法则是指我们在解决问题或达成某项目标的过程中所要完成的逐个步骤。一个好的算法必须要:
事实上,我们可以将烤制胡萝卜蛋糕的过程看成是一个算法:
如果这些步骤的顺序被改变了,厨师可能得到的就是一个滚烫的烤箱模具,里面放了一团鸡蛋与面粉的搅拌物。如果省去了其中的某一个步骤,那么厨师也不会烤成蛋糕,或许他只是点了一次火而已。当然,熟练的厨师通常是不需要这种算法的。但是,蛋糕制作原料的销售商可不能,也不该假设他们的客户都很熟练。总之,好的算法必须要按照恰当的顺序列出恰当的步骤,并且要详尽到足以完成任务。
自测题
1-4.烤制蛋糕的食谱通常会省略一个非常重要的动作,请指出上述算法中缺少的是什么动作。
通常情况下,算法中所包含的都是一些不涉及太多细节的步骤。例如,“在大碗中搅拌”并不是一个非常具体的动作描述,里面的食材配比是什么呢?如果我们现在的问题是要编写一个人类能够理解的蛋糕烤制算法,这个步骤就可以做进一步的改进,使其能指导厨师更好地安排食材配比。比如我们可以将该步骤改成“将牛奶倒入盛有鸡蛋与面粉的大碗中搅拌,直至其表面光滑”,或者为面包师将该步骤切分如下:
算法可以用伪代码来描述,甚至也可以用一种非程序员也能理解的语言来描述。由于伪代码面向的是人类,而不是计算机,因此用伪代码描述的算法在程序设计中是很有帮助的。
伪代码有极强的表达能力。一条伪代码通常可以表示多条计算机指令。另外,用伪代码来描述算法可以避免纠缠于标点错误或者与特定计算机系统相关的细节。用伪代码来描述解决方案允许我们将这些细节问题向后推,这可以让设计变得更容易一些。其实,写算法就相当于在做计划,程序开发者也可以用纸和笔来做这些设计,甚至有时可以直接在脑海中完成这些事。
留言与评论(共有 0 条评论) |