您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 质量控制/管理 > 最经典的c语言教程谭浩强c语言第2章
2.1算法的概念2.2简单算法举例2.3算法的特性2.4怎样表示一个算法2.5结构化程序设计方法习题第2章程序的灵魂——算法一个程序应包括以下两方面内容:(1)对数据的描述。在程序中要指定数据的类型和数据的组织形式,即数据结构(datastructure)。(2)对操作的描述。即操作步骤,也就是算法(algorithm)。数据是操作的对象,操作的目的是对数据进行加工处理,以得到期望的结果。作为程序设计人员,必须认真考虑和设计数据结构和操作步骤(即算法)。因此,著名计算机科学家沃思(NikiklausWirth)提出一个公式数据结构+算法=程序实际上,一个程序除了以上两个主要要素之外,还应当采用结构化程序设计方法进行程序设计,并且用某一种计算机语言表示。因此,可以这样表示:程序=算法+数据结构+程序设计方法+语言工具和环境也就是说,以上4个方面是一个程序设计人员所应具备的知识。在设计一个程序时要综合运用这几方面的知识。在这4个方面中,算法是灵魂,数据结构是加工对象,语言是工具,编程需要采用合适的方法。算法是解决“做什么”和“怎么做”的问题。程序中的操作语句,实际上就是算法的体现。显然,不了解算法就谈不上程序设计。我们的目的是使读者通过学习本书,能够知道怎样编写一个C程序,并且能够编写出不太复杂的C程序。书中将通过一些实例把以上4个方面的知识结合起来,介绍如何编写一个C程序。由于算法的重要性,在本章中先介绍有关算法的初步知识,以便为后面各章的学习建立一定的基础。2.1算法的概念从事各种工作和活动,都必须事先想好进行的步骤,然后按部就班地进行,才能避免产生错乱。不要认为只有“计算”的问题才有算法。广义地说,为解决一个问题而采取的方法和步骤,就称为“算法”。对同一个问题,可以有不同的解题方法和步骤。方法有优劣之分。有的方法只需进行很少的步骤,而有些方法则需要较多的步骤。一般说,希望采用简单的和运算步骤少的方法。因此,为了有效地进行解题,不仅需要保证算法正确,还要考虑算法的质量,选择合适的算法。本书所关心的当然只限于计算机算法,即计算机能执行的算法。计算机算法可分为两大类别:数值算法和非数值算法。数值运算的目的是求数值解。非数值运算包括的面十分广泛,最常见的是用于事务管理领域。目前,计算机在非数值运算方面的应用远远超过了在数值运算方面的应用。由于数值运算有现成的模型,可以运用数值分析方法,因此对数值运算的算法研究比较深入,算法比较成熟。对各种数值运算都有比较成熟的算法可供选用。人们常常把这些算法汇编成册(写成程序形式),或者将这些程序存放在磁盘或磁带上,供用户调用。而非数值运算的种类繁多,要求各异,难以规范化,因此只对一些典型的非数值运算算法(例如排序算法)作比较深入的研究。其他的非数值运算问题,往往需要使用者参考已有的类似算法重新设计解决特定问题的专门算法。本书不可能罗列所有算法,只是想通过一些典型算法的介绍,帮助读者了解如何设计一个算法,推动读者举一反三。希望读者通过本章介绍的例子了解怎样提出问题,怎样思考问题,怎样表示一个算法。2.2简单算法举例例2.1求1×2×3×4×5。可以用最原始的方法进行。步骤1:先求1×2,得到结果2。步骤2:将步骤1得到的乘积2再乘以3,得到结果6。步骤3:将6再乘以4,得24。步骤4:将24再乘以5,得120。这就是最后的结果。这样的算法虽然是正确的,但太繁琐。如果要求1×2×…×1000,则要写999个步骤,显然是不可取的。而且每次都直接使用上一步骤的数值结果(如2,6,24等),也不方便。应当找到一种通用的表示方法。可以设两个变量,一个变量代表被乘数,一个变量代表乘数。不另设变量存放乘积结果,而直接将每一步骤的乘积放在被乘数变量中。今设p为被乘数,i为乘数。用循环算法来求结果。可以将算法改写如下:S1:使p=1S2:使i=2S3:使p×i,乘积仍放在变量p中,可表示为p×i=pS4:使i的值加1,即i+1=iS5:如果i不大于5,返回重新执行步骤S3以及其后的步骤S4和S5;否则,算法结束。最后得到p的值就是5!的值。上面的S1,S2…代表步骤1,步骤2……S是step(步)的缩写。这是写算法的习惯用法。请读者仔细分析这个算法,能否得到预期的结果。显然这个算法比前面列出的算法简练。如果题目改为求1×3×5×7×9×11。算法只需作很少的改动即可:S1:1=pS2:3=iS3:p×i=pS4:i+2=iS5:若i≤11,返回S3;否则,结束。可以看出,用这种方法表示的算法具有通用性、灵活性。S3到S5组成一个循环,在实现算法时,要反复多次执行S3、S4、S5等步骤,直到某一时刻,执行S5步骤时经过判断,乘数i已超过规定的数值而不返回S3步骤为止。此时算法结束,变量p的值就是所求结果。由于计算机是高速进行运算的自动机器,实现循环是轻而易举的,所有计算机高级语言中都有实现循环的语句。因此,上述算法不仅是正确的,而且是计算机能实现的较好的算法。请读者仔细分析循环结束的条件,即S5步骤。如果在求1×2×…×11时,将S5步骤写成S5:若i<11,返回S3。这样会有什么问题?会得到什么结果?例2.2有50个学生,要求将他们之中成绩在80分以上者打印出来。用n表示学生学号,n1代表第一个学生学号,ni代表第i个学生学号。用g代表学生成绩,gi代表第i个学生成绩,算法可表示如下。S1:1=iS2:如果gi≥80,则打印ni和gi,否则不打印S3:i+1=iS4:如果i≤50,返回S2,继续执行;否则,算法结束。本例中,变量i作为下标,用它来控制序号(第几个学生,第几个成绩)。当i超过50时,表示已对50个学生的成绩处理完毕,算法结束。例2.3判定2000—2500年中的每一年是否闰年,将结果输出。闰年的条件是:①能被4整除,但不能被100整除的年份都是闰年,如1996年,2004年是闰年;②能被100整除,又能被400整除的年份是闰年。如1600年、2000年是闰年。不符合这两个条件的年份不是闰年。算法可表示如下:设y为被检测的年份。可采取以下步骤:S1:2000=yS2:y不能被4整除,则输出y“不是闰年”。然后转到S6S3:若y能被4整除,不能被100整除,则输出y“是闰年”。然后转到S6S4:若y能被100整除,又能被400整除,输出y“是闰年”;否则输出“不是闰年”。然后转到S6S5:输出y“不是闰年”S6:y+1=yS7:当y≤2500时,转S2继续执行,如y>2500,算法停止。在这个算法中,采取了多次判断。先判断y能否被4整除,如不能,则y必然不是闰年。如y能被4整除,并不能马上决定它是否闰年,还要看它能否被100整除。如不能被100整除,则肯定是闰年(例如1996年)。如能被100整除,还不能判断它是否闰年,还要被400整除,如果能被400整除,则它是闰年,否则不是闰年。在这个算法中,每做一步,都分别分离出一些范围(巳能判定为闰年或非闰年),逐步缩小范围,使被判断的范围愈来愈小,直至执行S5时,只可能是非闰年。见图2.1示意。图2.1从图2.1可以看出:“其他”这一部分,包括能被4整除,又能被100整除,而不能被400整除的那些年份(如1900年),是非闰年。在考虑算法时,应当仔细分析所需判断的条件,如何一步一步缩小被判断的范围。有的问题,判断的先后次序是无所谓的,而有的问题,判断条件的先后次序是不能任意颠倒的,读者可根据具体问题决定其逻辑。例2.4求1-1/2+1/3-1/4+…+1/99-1/100。算法可以表示如下:S1:1=signS2:1=sumS3:2=denoS4:(-1)×sign=signS5:sign×(1/deno)=termS6:sum+term=sumS7:deno+1=denoS8:若deno≤100返回S4;否则算法结束。在步骤S1中先预设sign(代表级数中各项的符号,它的值为1或-1)。在步骤S2中使sum等于1,相当于已将级数中的第一项放到了sum中。在步骤S3中使分母的值为2。在步骤S4中使sign的值变为-1。在步骤S5中求出级数中第2项的值-1/2。在步骤S6中将刚才求出的第二项的值-1/2累加到sum中。至此,sum的值是1-1/2。在步骤S7中使分母deno的值加1(变成3)。执行S8步骤,由于deno≤100,故返回S4步骤,sign的值改为1,在S5中求出term的值为1/3,在S6中将1/3累加到sum中。然后S7再使分母变为4。按此规律反复执行S4到S8步骤,直到分母大于100为止。一共执行了99次循环,向sum累加入了99个分数。sum最后的值就是级数的值。例2.5对一个大于或等于3的正整数,判断它是不是一个素数。所谓素数,是指除了1和该数本身之外,不能被其他任何整数整除的数。例如,13是素数,因为它不能被2,3,4,…,12整除。判断一个数n(n≥3)是否素数的方法是很简单的:将n作为被除数,将2到(n-1)各个整数轮流作为除数,如果都不能被整除,则n为素数。算法可以表示如下:S1:输入n的值S2:2=i(i作为除数)S3:n被i除,得余数rS4:如果r=0,表示n能被i整除,则打印n“不是素数”,算法结束;否则执行S5S5:i+1=iS6:如果i≤n-1,返回S3;否则打印n“是素数”,然后结束。实际上n不必被2到(n-1)的整数除,只需被2到n的开方间整数除即可,甚至只需被2到n之间的整数除即可。例如,判断13是否素数,只需将13被2、3除即可,如都除不尽,n必为素数。S6步骤可改为:S6:如果i≤n,返回S2;否则算法结束。通过以上几个例子,可以初步了解怎样设计一个算法。2.3算法的特性一个算法应该具有以下特点:1.有穷性一个算法应包含有限的操作步骤,而不能是无限的。事实上,“有穷性”往往指“在合理的范围之内”。究竟什么算“合理限度”,并无严格标准,由人们的常识和需要而定。2.确定性算法中的每一个步骤都应当是确定的,而不应当是含糊的、模棱两可的。3.有零个或多个输入所谓输入是指在执行算法时需要从外界取得必要的信息。一个算法也可以没有输入。4.有一个或多个输出算法的目的是为了求解,“解”就是输出。没有输出的算法是没有意义的。5.有效性算法中的每一个步骤都应当能有效地执行,并得到确定的结果。对于不熟悉计算机程序设计的人来说,他们可以只使用别人已设计好的现成算法,只需根据算法的要求给以必要的输入,就能得到输出的结果。对他们来说,算法如同一个“黑箱子”一样,他们可以不了解“黑箱子”中的结构,只是从外部特性上了解算法的作用,即可方便地使用算法。例如,对一个“输入3个数,求其中最大值”的算法,可以用图2.2表示,只要输入a,b,c3个数,执行算法后就能得到其中最大的数。但对于程序设计人员来说,必须会设计算法,并且根据算法编写程序。图2.22.4怎样表示一个算法为了表示一个算法,可以用不同的方法。常用的有自然语言、传统流程图、结构化流程图、伪代码、PAD图等。2.4.1用自然语言表示算法在2.2节中介绍的算法是用自然语言表示的。用自然语言表示通俗易懂,但文字冗长,容易出现“歧义性”。自然语言表示的含义往往不太严格,要根据上下文才能判断其正确含义。此外,用自然语言描述包含分支和循环的算法,不很方便(如例2.5的算法)。因此,除了很简单的问题以外,一般不用自然语言描述算法。2.4.2用流程图表示算法流程图是用一些图框表示各种操作。用图形表示算法,直观形象,易于理解。美国国家标准化协会ANSI(AmericanNationalStandardInstitute)规定了一些常用的流程图符号(见图2.3)。图2.3中菱形框的作用是对一个给定的条件进行判断,根据给定的条件是否成立来决定如何执行其后的操作。它有一个入口,两个出口。见图2.4。连接点(小圆圈)是用于将画在不同地方的流程线连接起来。如图2.5中有两个以○为标志的连接点(在连接点圈中写上“1”),它表示这两个点是互相连接在一起的。实际上它们是同
本文标题:最经典的c语言教程谭浩强c语言第2章
链接地址:https://www.777doc.com/doc-3683547 .html