考研计算机基础:构造算法与自上而下逐步完善:实例研究2

构造算法与自上而下逐步完善:实例研究2(标记控制重复)

下面将全班平均成绩问题一般化,考虑如下问题:

开发一个计算全班平均成绩的程序,在每次程序运行时处理任意个成绩数。

在第一个全班平均成绩例子中,成绩个数(10)是事先预置的。而本例中,则不知道要输入多少个成绩,程序要处理任意个成绩数。程序怎么确定何时停止输入成绩呢?何时计算和打印全班平均成绩呢?

一种办法是用一个特殊值作为标记值(sentinelvalue),也称信号值(signalvalue)、哑值(dummy value)或标志值(flag value),表示数据输入结束(“end of data entry”)用户输入成绩,直到输入所有合法成绩。然后用户输入一个标记值,表示最后一个成绩已经输入。标记控制重复(sentinel-controlled repetition)也称为不确定重复(indefinite repetition),因为执行循环之前无法事先知道重复次数。

显然,标记值不能与可接受的输入值混淆起来。由于考试成绩通常是非负整数,因此可以用-1作标记值。这样,全班平均成绩程序可以处理95、96、75、74、89和-l之类的输人流。程序计算并打印成绩95、96、75、74和89的全班平均成绩(不计入-1,因为它是标记值)。

常见编程错误2.8

将选择的标记值与可接受的输入值混淆时会造成逻辑错误。

我们用自上而下逐步完善(top-down,stepwise

refinement)的方法开发计算全班平均成绩的程序,这是开发结构化程序的重要方法。我们首先生成上层伪代码表示:

  Determine  the  class  avcraqe  for  the quiz

上层伪代码只是一个语句,表示程序的总体功能。这样.上层等于是程序的完整表达式。但上层通常无法提供编写C++程序所需的足够细节。因此要开始完善过程。我们将上层伪代码分解为一系列的小任务,按其需要完成的顺序列出。这个结果就是下列第一步完善(first,refinement):

Initialize variables
    Input,sum,and count the quiz grades
    Calculate and print the class average

这里只用了顺序结构,所有步骤按顺序逐步执行。

软件工程视点2.4

上层伪代码及每一步完善都是算法的完整定义,只是详细程度不同而已。

软件工程视点2.5

许多程序可以在逻辑上分为三个阶段:初初化阶段将程序变量初始化,处理阶段输入数据值和相应调整程序变量,结束阶段计算和打印最后结果。

上述“软件工程视点”通常是自上而下过程第一步完善的全部工作。要进行下一步完善(即第二步完善,second

refinement),我们要指定特定变量,要取得数字的动态和以及计算机处理的数值个数,用一个变量接收每个输入的成绩值,一个变量保存计算平均值。下列伪代码语句:

      Initialize variables

可以细化成:

 Initialize total to zero
    Initialize counter to zero

注意,只有total和counter变量要先初始化再使用,average和grade变量(分别计算平均值和用户输入)不需要初始化.因为它们的值会在计算或输入时重定义。

下列伪代码语句:

Input, sum, and count the quiz grades

需要用重复结构(即循环)连续输入每个成绩。由于我们事先不知道要处理多少个成绩,因此使用标记控制重复。用户一次一项地输入合法成绩。输入最后一个合法成绩后,用户输人标记值。程序在每个成绩输入之后测试其是否为标记值.如果用户输入标记值,则顺序循环终止。上述伪代码语句的第二步完善如下:

   Input the first grade (possibly the sentinel)
    While the user has not as yet entered the sentinel
   Add this grade into the running total
    Add one to the grade counter
    Input the next grade (possibly the sentinel)

注意,在这个伪代码中,我们没有在while结构体中使用花括号,只是在while下面将这些语句缩排表示它们属于while。伪代码只是非正式的程序开发辅助工具。

下列伪代码语句可以完善如下:

 If the counter is not equal to zero
     Set the average to the total divided by the counter
     Print the average
    else
      Print "No grades were entered"

注意我们这里要测试除数为0的可能性,这是个致命逻辑错误,如果没有发现,则会使程序失败(通常称为爆炸或崩溃)。图2.8显示了全班平均成绩问题第二步完善的完整伪代码语句。

常见编程错误2.9

除数为0是个致命逻辑错误。

编程技巧2.9

进行除法时,要测试除数为0的可能性,并在程序中进行相应处理(如打印一个错误消息).而不是让致命逻辑错误发生。

图2.6和图2.8的伪代码中增加了一些空行,使伪代码更易读。空行将程序分成不同阶段。

图2.8所示的伪代码算法解决更一般的全班平均成绩问题,这个算法只进行了第二步完善,还需要进一步完善。

 Initialize total to zero
    Initialize counter to zero

    Input the first grade (possibly the sentinel)
    While the user has not as yet entered the sentinel
       Add this grade into the running total
       Add one to the grade counter
       Input the next grade (possibly the sentinel)

    if the counter is not rqual to zero
       Set the average to the total divided by the counter
       Print the average
    else
       Print "No grades were entered"

图2.8 用标记符控制重复解决全班平均成绩问题的伪代码算法

软件工程视点2.6

伪代码算法的细节足以将伪代码变为C++代码时,程序员即可停止自上而下逐步完善的过程,然后就可方便地实现C++程序。

图2.9显示了C++程序和示例执行结果。尽管只输入整数成绩,但结果仍然可能产生带小数点的平均成绩,即实数。int类型无法表示实数,程序中引入float数据类型处理带小数点的数(也称为浮点数,floatingpoint number),并引入特殊的强制类型转换运算符(cast operator)处理平均值计算。这些特性将在程序之后详细介绍。

// Fig. 2.9: fig02_09.cpp
// Class average program with sentinel-controlled repetition.
#include <iostream.h>#include <iomanip.h>
int main()
{
	int total,    // sum of grades
	gradeCounter, // number of grades entered
	grade;      // one grade
	float average;  // number with decimal point for average
	// initialization phase
	total = 0;
	gradeCounter = 0;
	// processing phase
	cout << "Enter grade, -1 to end: ";
	cin >> grade;
	while ( grade !=-1 ) {
		total = total + grade;
		gradeCounter = gradeCounter + 1;
		cout << "Enter grade, -1 to end: ";
		cin >> grade;
	}
	// termination phase
if ( gradeCounter != 0 } {
	average - static_cast< float >( total ) / gradeCounter;
	cout << "Class average is "<< setprecision{ 2 )
		<< setiosflags( ios::fixed | ios::showpoint )
			<< average << endl;
		}
		else
			cout << "NO grades were entered" << endl;
			return 0;        // indicate program ended successfully
		}

输出结果:

   Enter grade, -1 to end: 75
    Enter grade, -1 to end: 94
    Enter grade, -1 to end: 97
    Enter grade,-1 to end: 88
    Enter grade, -1 to end: 70
    Enter grade, -1 to end: 64
    Enter grade, -1 to end: 83
    Enter grade, -1 to end: 89
    Enter grade, -1 to end: -1
    Class average is 82.50

图2.9 用标记符控制重复解决全班平均成绩问题的C++程序和示例执行结果

注意图2.9中while循环中的复合语句。如果没有花括号,则循环体中的最后三条语句会放到循环以外,使计算机错误地理解如下代码:

   while { grade ! = -1 )
       total - total + grade;
    gradeCounter = gradeCounter + 1;
    cout << "Enter grade, -1 to end:";
    cin >> grade;

如果用户输入的第一个成绩不是-l,则会造成无限循环。

注意下列语句:

   cin >>grade;

前面用一个输出语句提示用户输入。

编程技巧2.10

提示用户进行每个键盘输入。提示应表示输入形式和任何特殊输入值(如用户终止循环时输入的标记值)。

编程技巧2.11

在标记控制循环中,提示请求输入数据项目时应显式指定标记值是什么值。

平均值并不一定总是整数值,而常常是包含小数的值,如7.2或-93.5。这些值称为浮点数,用数据类型float表示。变量average声明为数据类型float,以获得计算机结果中的小数。但total/gradeCounter的计算结果是整数,因为total和gradeCounter都是整数变量。两个整数相除是整除(integer

division),小数部分丢失(即截尾,truncated)。由于先要进行计算,因此小数部分在将结果赋给average之前已经丢失。要用整数值进行浮点数计算,就要先生成用于计算的临时浮点数值。

C++提供了一元强制类型转换运算符(unary cast operator)。下列语句:

average = static cast< float >(total) /gradeCounter;

包括一元强制类型转换运算符static_cast<float>(),生成用于计算的临时浮点数值(total)。这样使用强制类型转换运算符称为显式类型转换(explicit conversion)。total中存放的值还是整数,而计算时则用浮点数值(total的临时float版本)除以整数gradcCounter。c++编译器只能对操作数的数据类型一致的表达式求值。要保证操作数的数据类型一致,编译器对所选择的操作数进行提升(promotion)操作(也称为隐式类型转换,implicit conversion)。例如,在包含数据类型float和int的表达式中,int操作数提升为float。本例中,gradeCounter提升为float之后进行计算,将浮点数除法得到的结果赋给average。本章稍后将介绍所有标准数据类型及其提升顺序。任何数据类型都可用强制类型转换运算符,static_cast运算符由关键字statlc cast加尖括号(<>)中的数据类型名组成。强制类型转换运算符是个一元运算符(unary perator),即只有一个操作数的运算符。第1章曾介绍过二元算术运算符。C++也支持一元正(+)、负(-)运算符,程序员可以编写-7、+5之类的表达式。强制类型转换运算符从右向左结合,其优先级高于正(+)、负(-)运算符等其他一元运算符,该优先级高于运算符*、/和%,但低于括号的优先级。优先级表中用static_cast<type>()表示强制类型转换运算符。

图2.9中格式化功能将在第11章详细介绍,这里先做一简要介绍。下列输出语句中调用

 setpreclslon(2):
        cout<<"Class average is" << setprecision(2)
        << Setiosflaqs(iOS::fixed |iOS::showpoint)
        << averaqe<< endl;

表示float变量average打印小数点右边的位数为两位精度(precision),例如92.37,这称为参数化流操纵算子(parameterized stream manipulator)。使用这些调用的程序要包含下列预处理指令:

        #include<iomanip.h>

注意endl是非参数化流操纵算子(nonparameterized stream manipulator),不需要iomanip.h头文件。如果不指定精度,则浮点数值通常输出六位精度(即默认精度,default precision),但稍后也会介绍一个例外。上述语句中的流操纵算子setiosflags(ios::fixed |ios::showpoInt)设置两个输出格式选项ios::fixed和ios::showpoint。垂直条(1)分隔setiosflags调用中的多个选项(垂直条将在第16章详细介绍)。选项ios::fixed使浮点数值以浮点格式(而不是科学计数法,见第ll章)输出。即使数值为整数,ios::showpoInt选项也会强制打印小数点和尾部O,如88.OO。如果不用ios::showpoint选项,则C++将该整数显示为88,不打印小数点和尾部o。程序中使用上述格式时,将打印的值取整,表示小数点位数,但内存中的值保持不变。例如,数值87.945和67.543分别输出为87.95和67.54。

常见编程错误2.10

如莱在使用浮点敷时认为其精确地表示了敷值.则全得到不正确的蛄柬。浮点敷雇大多数计算机上都采用近似表示。

编程技巧2.12

不要比较浮点数值的相等和不等性,而要测试差值绝对值是否小于指定的值。

尽管浮点数算不总是100%精确,但其用途很广。例如,我们说正常体温98.6(华氏温度)时,并不需要精确地表示,如果温度计上显示98.6度.实际上可能是98.5999473210643度。这里显示98.6对大多数应用已经足够了。

另一种得到浮点数的方法是通过除法。10除以3得到3.333333……,是无限循环小敷。计算机只分配固定空间保存这种值,因此只能保存浮点值的近似值。

2016考研复试技巧http://www.kyjxy.com/fushi/zhinan/
考研专硕备考资料http://www.kyjxy.com/zhuanshuo/
考研院校政策http://www.kyjxy.com/yuanxiao/zhengce/

时间: 2024-11-08 06:37:15

考研计算机基础:构造算法与自上而下逐步完善:实例研究2的相关文章

考研计算机基础构造算法的实例研究

构造算法:实例研究1(计数器控制重复) 要演示如何开发算法,我们要解决几个全班平均成绩的问题.考虑下列问题: 班里有10个学生参加测验,可以提供考试成绩(0到100的整数值),以确定全班平均成绩. 全班平均成绩等于全班成绩总和除以班里人数.计算机上解决这个问题的算法是辅人每人的成绩,进行平均计算,然后打印结果. 下面用伪代码列出要执行的操作,指定这些操作执行的顺序.我们用计数器控制重复(counter-conttrolled repetition)一次一个地输人每人的成绩.这种方法用计数器(co

考研计算机基础while重复结构

while重复结构 重复结构(repetition strucure)使程序 员可以指定一定条件下可以重复的操作.下列伪代码语句: While there are more items on my shopping list Purchase next item and cross it off my list 描述购物过程中发生的重复.条件"there are more ltems on my shopping list"(购物清单中还有更多项目)可真可假.如果条件为true.则执行

考研计算机基础2.6 if/else选择结构

if选择结构只在条件为true时采取操作,条件为false时则忽略这个操作.利用if/else选择结构则可以在条件为true时和条件为false时采取不同操作.例如,下列伪代码: if student's grade is greater than or equal to 60 print "Passed" else print "Failed" 在学生成绩大于或等于60时打印“Passed”,否则打印"Failed".打印之后,都“执行”下一条

计算机基础课程对编写代码有多大影响

相信很多计算机专业刚步入社会开始编程工作的同学都有一个疑惑,大学四年学的计算机基础课程对编程来说几乎用不上,远远没有C/C++.Java.Java Web.sql有用.我当时也有这样的疑惑,因为大部分程序员刚开始工作的任务仅仅只是在别人搭好的框架下,在合适的地方添加上合适的代码,实现某个功能.在这个阶段有这样的疑惑是可以理解的,因为只是在山脚下看问题,不知庐山真面目.在这个阶段有些有心的同学可能会在编码过程中考虑下性能(方法级别的性能),合理使用集合类,合理采用一些算法,减少循环次数和时间复杂度

程序员必须知道的10大基础实用算法及其讲解

程序员必须知道的10大基础实用算法及其讲解 原文出处: cricode 算法一:快速排序算法 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比 较,但这种状况并不常见.事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构 上很有效率地被实现出来. 快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子

程序员必知的10大基础实用算法

    算法一:快速排序算法 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2) 次比较,但这种状况并不常见.事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的 架构上很有效率地被实现出来. 快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists). 算法步骤: 1 从数列中挑出一个元

十大基础实用算法之快速排序和堆排序

快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来. 快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists). 算法步骤: 1 从数列中挑出一个元素,称为 "基准"(pi

如何成为一名黑客(网络安全从业者)——计算机基础知识篇

大家好,我是Mr.Quark,大家可以叫我夸克,欢迎大家在微信公众号(Quark网络安全)上给我留言,如果有时间我一定会一一回复大家的.今天我将和大家一起学习"如何成为一名黑客"或者说"如何成为一名网络安全专家". 在进入正题之前,我们先来给黑客下一个定义,毕竟如果连黑客的含义都不了解,成为黑客更是无从谈起. "黑客"称呼的变迁 在很久很久以前(别问我有多久,不要在意这些细节),"黑客"指的是喜爱钻研技术.精通计算机技术的程序

计算机基础之计算机硬件软件数据结构

一切生产工具都是人类器官功能的延伸,智力活动弥补体力劳动的不足:一切交通工具都是腿力的延伸:一切机床都是手力的延伸:望远镜.显微镜.电视 都是眼力的延伸:电话.收音机.通讯卫星都是耳力的延伸:计算机系统便是人类思维器官--大脑的延伸. 第一部分.计算机基础 1.为什么计算机能够进行脑力劳动? 计算机是一种可进行快速运算的可存储设备.存储的程序保证了运算的自动性,从而减轻脑力劳作. 2.计算机发展到今天,跟传统的图灵机相比最大的突破在什么地方?最大的限制又在哪里?你觉得未来计算机发展方向? 传统的