循环结构的三要素及其他
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
循环结构的三要素及其他
摘要:循环结构是结构化程序设计中最为复杂的一种结构,本文提出构成循环结构的三个要素,论述运用循环结构三要素进行程序设计的方法,以及循环与递归的关系。
关键词:算法;程序结构;循环;递归
1问题的提出
结构化程序设计中,只有三种基本的结构:顺序、选择和循环。
顺序结构是程序设计过程中自然形成的,也是三种结构中最简单的一种。选择结构与我们日常中使用的自然语言“如果...则...否则...”十分相近,只是其嵌套时的二义性在形式上必须有一个明确的规定。
而循环结构是三者中最为复杂的,也是使用最多的。一个算法往往要用循环结构来描述,一个程序能否正确编写又往往取决于对循环结构的正确理解和使用。因此,有必要深入对循环结构做一个分析。本文从循环结构的三个要素、循环结构与程序的阅读、循环与递归的联系等三个方面进行分析与论述,而这些在目前的教学中往往很少提到,甚至是被忽略的。
2循环结构的三要素
初学程序设计的人,对于如何在程序中使用循环结构实现算法,总觉得不知从何入手,有时即使编出程序,也不尽人意。下面我们从一个简单的典型实例说起。为了说明问题,本文对有关编程的问题都以C语言函数的方式列出解答。
2.1一个典型实例及其两种解答
例2.1鸡兔同笼,有h个头,f只脚,求鸡兔各多少。这是我国古代一个典型的算术问题。现在要设计一个函数,求出兔子的数目(求出兔子的数目,自然就可以得到鸡的数目)。不妨设这个函数为:
int hab(int h, int f);
函数的定义如下:
int rabbit (int h, int f)// h为头数, f为脚数
{
int i;
i=h;
while (i>=0 )
{
if (i*4+(h-i)*2==f) break;
i--;
}
return i; //-1表示该该问题无解。
}
这个程序的运行结果是正确的,但是很遗憾,这并不是一个完美的程序,尽管很多教科书也是这样写的。我们再来看看下面的另一种解法:
int rabbit (int h, int f)// h为头数, f为脚数
{
int i;
i=h
while((i>=0)&& (i*4+(h-i)*2!=f ))
i--;
return i;//-1表示该问题无解。
}
以上两个程序都用到循环结构,第一个程序在循环结构中嵌套了一个选择结
构,并且使用了break语句。而在第二个程序中,无需这样做。无论从程序的结构,还是从程序的可读性来说,后者显得比前者要好得多。那么问题出在哪里呢?
2.2深入分析
比较两个程序可以发现,关键是对条件表达式(i*4+(h-i)*2!=l)的运用。前者把条件表达式放在循环体中,后者把它作为循环条件。看来,有必要对循环结构做深入的分析。
不管一个循环结构有多复杂,都可以从以下三个方面来分析:
1) 初始状态:所有参与循环的变量在循环之前都必须有一个确定的值。
2) 循环条件:当条件满足时,循环继续,否则循环终止。循环条件应是一个逻辑表达式。
3) 循环体:每次循环要执行的语句。
这就是我们所讲的循环结构三要素。从这个角度再来分析上面的例子,就很容易找到问题的结症:(i*4+(h-i)*2!=l)是循环条件之一,因此不应放在循环体内使用。第一种方法虽然也能得到正确的结果,但并不是好的方法,甚至是不正确的方法。
2.3一个应用实例
例2.2 裴波那契序列数的递归表示如下:
f0=0
f1=1
fn=fn-2+fn-1(n>=2)
对于任意给定的正整数x,判别其是否在裴波那契序列中。
现在要求判别一个给定的正整数x是否在裴波那契序列中,一个直观的判别方法是从f0和f1出发,不停地求后面的裴波那契序列数。每得到一个裴波那契序列数,就同这个待判别数进行比较,直到相等时输出“真”。或当得到一个裴波那契序列数大于这个待判别数时,输出“假”。
要实现这个算法,需用到循环结构。我们来分析一下这个循环结构的三个要素:
(1) 初始状态:f0=0; f1=1,x=?;
(2) 循环条件:当前求得的裴波那契序列数0时,计算的是n和m%n的最小公倍数。显然,这时的两个正整数要比原来的两个正整数(m, n)要小,计算也变得容易一些。
通过以上的例子,我们可以这样来理解递归的意义:把一个复杂的、规模较大的问题转化为简单的、规模较小的同一个问题,直至可以直接得到问题的解。
4.2用递归函数取代循环结构
一个程序如果可以用循环结构来实现,那么也可以用一个递归函数来实现。我们先来看一个简单的例子。
例4.3求一个有n个元素的数组中的最大元素。
用循环结构的方法如下:
int max(int a[])
{
int i, m;
m=a[0]
for (i=1; i<10,i++)
if(max<a[i])m=a[i];
return m;
}
用递归函数。设一递归函数max(a,k)是求a数组中第k个元素及其后所有元素的最大者:
a[k]k=n-1;
max(a,k)= {
a[k]>max(a,k+1)?a[k]:max(a,k+1) k<n-1
用C语言编写的函数如下:
int max(int a[], int k, int n)
{ int m;
if (k==n-1)return ( a[k] )
else {m=max(a,k+1);
return ( a[k]>m?a[k]:m ); }
}
这是一个简单的例子,下面再看一个较为复杂性的例子。
例4.4用递归函数求解例2.1。
用递归函数来求解例2.1,应如何考虑呢?正如以上所说,递归的意义是把一个复杂的、规模较大的问题转化为简单的、规模较小的同一个问题,直至可以直接得到问题的解。因此我们可以这样来考虑:把笼中的一只鸡抓走,笼中的兔子的数目是不变的,显然这仍然是鸡兔同笼的问题,但少了一只鸡,问题就变得简单了一点。当所有的鸡都被抓走时,剩下的都是兔,这时就可以直接得到答案——腿数除以头数就是兔子的数目。
我们用robb(h,g)这样一个函数表示求兔子的数目,参数h、g分别表示头数和腿数,因此有:
robb(x,y)=robb(x-1,y-2)
但在什么情况下能直接得到结果呢?显然,当鸡全部抓走只留下兔子时,就可以直接得到答案,这时腿数应是头的4倍:
roob(x,y)=x当4*x=y
另外还要考虑在什么情况下问题没有解。显然,当4*h<g时,这个问题无解。
x4*x=y
robb(x,y)={ robb(x-1,y-2)4*x>y
-1 4*x<y(-1表示问题无解)
在求得兔子的数目之后,只要用总数减去兔子的数目,就能求出鸡的数目。