4.7 判断三角形种类

题目:输入3个整数,判断以下两个问题。

(1)能否以此三个数为边长构成一三角形?

(2)如果能构成一三角形,那么是什么样的三角形(等边、等腰、等腰直角、直角、锐角、钝角)?

分析如下。

首先应该考虑的是程序的数据类型的设计及常量、变量的命名等问题。一旦数据类型选择不当,要么程序还没编写就已经错了,要么要多走不少弯路。好在此题目的数据类型已经很明确了,这件事情容易解决(7)

由于数学中三角形的边通常用a、b、c表示,所以在代码中也可以这样命名。

代码极少有“顷刻而就,文不加点”一次性写成的,至少不可能一次写的很好。这个道理不需要什么智商就能理解。当然,代码写多了,写一些简短的代码是能够一蹴而就的,但这是另一回事情。下面涉及的是多数人都可能遇到的问题。

不少人在写代码时完全想不起或没想到下面一些事实:只有正数才可能成为三角形的边长;平面几何中的“两边之和大于第三边”本质上说的是“任意”“两边之和大于第三边”,这其实是三个必须同时成立的条件。而一旦领悟到构成三角形的判断条件是多个条件的组合时,会发现在写代码时有不胜其繁的感觉。“繁”则思变,你会发现在判断之前对3个整数按照由小到大排个顺序会使代码简洁许多。

要是你没想到这么多也不要气馁,除了极少数训练有素的程序员,很少有人能一下子想得如此全面周到,尤其是那些拿过题目很快开始匆匆写代码的人。见过要求编程求两个数之和的题目,很多人能立刻给出代码。实际上,这种代码是写不出来的,因为题目并没有说是两个什么样的“数”(8)。很多人能很快写出错误题目的程序代码,一直是让我瞠目结舌的。弄清题目的真正要求,从来不是一件很容易的事情。

理解题目要求,确定程序的功能是编程的第一个步骤,本书中称之为“程序功能定义”。

定义程序功能时,需要设想一下程序的输入与输出。就本题目而言至少要事先设计出能构成三角形的输入数据和不能构成三角形的数据,以及能构成各种三角形(等边、等腰、等腰直角、直角、锐角、钝角)的数据(把它们记在纸上)。这不但是程序完成后进行测试的要求,对设计程序的算法和数据结构(类型)也很有帮助。

在设计程序的算法和数据结构(类型)时,在纸上写一些伪代码或画画N-S图往往有助于更深入更周密的思考,能起到事半功倍的效果。如图4-3所示,是程序的N-S图。

4.7 判断三角形种类 - 图1

图4-3 三角形问题N-S图

没必要一次给出全部的细节,但首先要从大处着眼,保证整体上结构的正确性与合理性。这就是所谓的“自顶向下,逐步细化”的思考模式。

在对整体结构有充分把握的条件下,甚至就可以开始(或试写)写代码了。写代码时应注意控制语句与流程图的对应关系。

程序代码4-8

4.7 判断三角形种类 - 图2

4.7 判断三角形种类 - 图3

这段未完全完成的代码的意义在于你马上就可以进行测试(前期准备的测试数据的意义由此可以体现)。如果代码有问题,可能会在第一时间被发现而得到及时的修正。不要等到问题成堆的时候再去debug(9)。我坚信,如果代码中有两个错误,调试的难度通常不是有一个错误时的两倍,而是它的平方。同样,错误被发现的越晚,修改它的成本越高。很多软件是带“病”发行的,不是问题没被发现,而是因为成本问题而无法修改。

如果这段代码没有什么问题被发现,毫无疑问将增强编程者的自信。“积小胜为大胜”,编程其实也是如此。而做到这一切,除了按照“自顶向下,逐步细化”的模式进行工作,我想不出还有什么别的办法。

如图4-4所示,是完成三角形种类的判断。如何对各种情况进行一分为二的分类是设计时应该重点考虑的内容。这可以有多种方式。本例题中的分类是直角三角形与非直角三角形,在非直角三角形中再分为钝角与锐角……当然,你也可以采用别的你感觉更有条理的方式分类。

4.7 判断三角形种类 - 图4

图4-4 判断三角形类型N-S图

其中的逻辑关系请自己参详。编写代码时,依然是按照前面的原则参照N-S图及写if-else语句的良好风格有条理地进行。下面是完成的代码,其中增加了一个变量delta记录a2+b2-c2的值,因为没必要每次判断时都计算这个值,这是“以空间换时间”战略原则的编程体现。

程序代码4-9

4.7 判断三角形种类 - 图5

4.7 判断三角形种类 - 图6

4.7 判断三角形种类 - 图7

测试:本题目的输入与输出都有多种情况,因此测试比较复杂。设计测试数据,最基本的一个思考原则就是各种情况至少有一组输入数据。此外,在输入数据时,应该首先对结果有所预测,而不是在程序输出之后再去校验。下面是一系列测试数据及结果。

4.7 判断三角形种类 - 图8

4.7 判断三角形种类 - 图9

练习

1.自行完成本小节例题,可以参考N-S图,但不要照样抄写代码(抄写代码的结果将会是使更调试困难)。

2.输入分别代表月、日的两个正整数,判断是否是某年的(比如2009年,已知2009年不是闰年)一个合法的日期。