深入“自顶向下,逐步求精”——面向过程程序设计方法
程序设计初学者常常受困于不会想问题:“不知道让计算机解决这个问题该如何做”。其实,程序员的一个基本功是,能够将复杂的问题分解开来。学会分解任务,因超级大分为大的、中的、小的、超小的,直到能用很直接的方法解决。记住一个很管用的策略:自项向下,逐步求精。不管做何事,都拿这个策略套一套,程序能编好,其他事也都能做。
本讲的主要目标在于:
(1)让你建立“自顶向下,逐步求精”的思维方式,你的大脑先能“机械化”,为指挥计算机“一步一步”地完成任务打下基础;
(2)让循环的概念在头脑中扎根:在顺序、选择、循环三种控制结构中,循环是最复杂的(只要你掌握了,也就不复杂,而成为一种自然的思维方式了),也是解决问题的最有效的结构,我们就先在此力求先期得到体会。
(3)C++程序的基本单位是函数,用函数解决更小的问题,这是求精实现的途径。
这部分内容并未对应到课本上的某一段。要学会“跳跃”的学习方式,自己构建知识,跳出所谓课本的框框。课本给出了一种知识的组织形式,然而知识本身并不本来就呈现这种关系的,这样组织只是作者的一种思路而已。工科学生要学会查阅资料,因为你所需的知识“背”不会,也不应该是用“背书”的方式学的。将课本看成是手册、工具书,无论学到哪儿,能随时恰当、准确地找到书中能够给你启示和参考的地方。不要迷信老师讲过就如何如何,只要你需要,消除心理障碍,你就能读下去,获得自己需要的知识。
先探讨一个最典型的用循环解决的问题。重点是从中体会用多种方式表示对同一个问题的解决。实际上,我们需要做到的是,很熟练地用随便一种方式将脑袋里形成想法表达出来。
【例1】求1+2+3+…+100
解题思路为:
设:和用sum表示,循环100次,第i次循环将i累加到sum sum初值为0; i初始为1,每循环一次增加1,直到100下面是解决这个问题的算法的不同描述形式:
用while循环语句写的程序
#include iostream using namespace std; int main( ) int i=1,sum=0; while (i =100) { sum=sum+i; i++; cout "sum=" sum endl; return 0;用for循环语句写的程序
#include iostream using namespace std; int main( ) int i,sum=0; for (i=1;i =100;i++) sum=sum+i; cout "sum=" sum endl; return 0;后面遇到的问题,会用一种形式写出来了,学着用其他方式写一写,用不了多久,脑子就活起来。
下面,我们用例子体验开始“自顶向下,逐步求精”。如果你现在已经能顺利编出这些程序,也需要再次体会这种思维。
【例2】在屏幕上输出如图所示的星号图形
程序员不能只看到一堆星星,要用分解的思想,整理出关于图的规律来,或者说,会分层次地看这个问题。这要训练“自顶向下,逐步求精”的思维方式。
思路:首先看到的是一个图;这个图有6行;每一行有若干个星号。可喜的是,每一行星号的个数还有规律:第i行星号的个数是2*i-1个!
算法就出来了:
输出6行星号这是我们“自顶向下,逐步求精”的第一次分解:将一个图分成了若干行;
输出6行用一个循环结构解决,循环每执行1次就输出1行,写成伪代码是:
//程序片段(1) While(i =6) 输出第i行; i=i+1; }“输出第i行”的问题还需要分解下去。实际上,输出“输出第i行”就是要“重复输出2*i-1个星号”,也用一个循环结构完成。
//程序片段(2) While(j =2*i-1) 输出一个*; j=j+1;将程序片段(1)中的“输出第i行”替换为程序片段(2),整个算法也就清晰了。
i=1; While(i =6) j=1; While(j =2*i-1) 输出一个*; j=j+1; 换行 i=i+1;用图示再表达一次上述过程,体会“自顶向下,逐步求精”。
我们可以写出完整的算法,据此写程序也就容易了。无论用while语句,还是for语句。
//用while循环的程序 #include iostream using namespace std; int main( ) int i,j,n=6;//n可以赋别的值 i=1; while(i =n) j=1; while(j =2*i-1) { cout *; j++; } cout endl; i++; return 0;
体会本例的任务:将输出一个“星号组成的图案”,分解为“循环输出若干行”,找出各行的规律,能够逐步细化到“输出第i行”这个任务,最终问题细化到只输出一个字符’*’。从“顶层”出发,“向下”(即编程中能直接实现的细节)考虑,“逐步”地“求精”得到达到用C++语句直接描述的程度。对复杂的问题,可能需要更多层次的分解。想一想,我们做任何工作,对大学生活做一宏观的规划、制定一天的学习计划、组织一次班级活动、将来的工程项目开发、做老板后策划一项商业活动、做官员后……无论复杂还是简单,有意或无意地,都是在“自顶向下,逐步求精”的伟大思想的光芒中行走的。只是现在,你需要用心体会,将其成为你的思维惯性。好了,回到技术层面,请用N-S图和流程图表示输出星号图的算法。直接用代码的形式在解决大问题时并不总是有效,学会这种表达方法仍是必要的。我们在实践中学习。
接下来,进一步体验让“自顶向下,逐步求精”更加灿烂的程序部件——函数。请阅读下面的两个函数的定义:
//(1)定义能输出一行m个星号的函数 void printstar(int m) int j=1; while(j =m) cout *; j++; cout endl; }
//(2)定义在当前行能输出若干指定符号的函数 void printch(char c, int m) int j=1; while(j =m) cout c; j++; cout endl; }读懂这段代码应该已经不算难事。接下来,试着在程序中,引入某个函数为你服务吧。比如,可以像下面的程序:
//while循环中调用函数的程序 #include iostream using namespace std; int main( ) int i,n=6; i=1; while(i =n) printstar(2*i-1);//调用函数 i++; return 0; }这段代码的功能与前面完全一样,但由于用函数printstar(2*i-1);完成若干个星号的输出,显然,程序简洁了很多。
还可以这样写:
//while循环中调用函数的程序 #include iostream using namespace std; int main( ) int i,j,n=6; for(i=1;i i++) printch(*,2*i-1); return 0; }这时,功能与上述是一样的,换了种循环语句,程序更短些,更重要的是,for循环适合于这种循环次数固定的问题。“计数型”循环用for,要习惯这样。
另外,printch(*,2*i-1);要换成printch(#,2*i-1);呢?输出的是#号图!我们可以很方便地输出其他符号的图。函数就是专门为完成一些通用任务而设的,函数就是为“自顶向下,逐步求精”而生的。
在面向过程的结构化程序设计中,“模块”是构成程序的基本单元,好比是一座大楼中的各个房间,有办公室、实验室、会议室、门房,各自独立,但共同组成了大楼。有了这样的模块,程序不需要写得很长,将一段功能独立的代码写成一个函数,让别的函数调用就是了(冒昧地用上术语了,定义的函数是要被调用的,于是有了主调函数和被调函数,如例子中,主调函数是main(),被调函数,你懂的)。在对问题分解后,并不一定需要把各级分解的结果堆在一起,组装出一个长长的貌似高水平的程序。“简单”是工程中的第一法则,用函数构造出的程序,结构简单、易读,易于多人合作分工完成,好处是不容易出错,将来的维护也就容易了。
本节练习:输出各种星号图。针对任务设计算法,并画出流程图。实现时,可以编出不使用函数和使用函数的两种版本。
每做出一个程序,停下来再看一看程序,默念“自顶向下,逐步求精”。
【编程思想】自顶向下 逐步求精 面向过程化编程思想:自顶向下 逐步求精 从程序执行的过程入手,将完整的过程细化成多个子过程,再将子过程细化,直到完成代码。
怎么理解面向对象和面向过程到底的本质区别? . 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。 面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
1.命名空间 namespace :C++引入的用于解决多个模块间命名冲突问题的一个机制,他是一个由程序设计者命名的内存区域,程序设计者可以根据需要指定一些有名字的空间域,把一些全局实体分别放在各个命名空间中,从而与其他全局实体分隔开来。
《面向对象分析与设计》一1.2 面向对象的基本思想 本节书摘来自华章出版社《面向对象分析与设计》一书中的第1章,第1.2节,作者 麻志毅,更多章节内容可以访问云栖社区“华章计算机”公众号查看
贺利坚 烟台大学计算机学院教师,建设系列学习资源,改革教学方法,为IT菜鸟建跑道,让大一的孩子会编程,为迷茫的大学生出主意,一起追求快乐的大学。 著书《逆袭大学:传给IT学子的正能量》,帮助处于迷茫中的大学
相关文章
- 深入理解jquery新的绑定事件机制on方法的使用
- Java抽象类深入理解-----模板方法设计模式(Templete Method)
- Extjs 基础篇—— Function 能在定义时就能执行的方法的写法 function(){...}()
- 深入类的方法
- 十四个方法提高博客的页面访问量
- 深入理解node.js的module.export 和 export方法的区别
- Python深入学习之特殊方法与多范式
- Web乱码解决方法
- [Java] Object有哪些公用方法?
- golang入门:for...range修改切片中元素的值的另类方法
- 162. 通过一个具体的例子,深入了解 SAP UI5 控件数据双向绑定的工作原理和问题排查方法
- 通过一个具体的例子,深入了解 SAP UI5 控件数据双向绑定的工作原理和问题排查方法试读版
- 如何根据ABAP类的一个方法名称,反查出这个类的名称
- Android问题笔记 - Only one Looper may be created per thread解决方法
- Java中的抽象类和抽象方法是什么?概述到解析层层深入了解
- oninput,onpropertychange,onchange的使用方法和差别
- 对Object类中方法的深入理解
- PostgreSQL的学习心得和知识总结(七十八)|深入理解PostgreSQL数据库客户端工具psql 添加 SHOW_ALL_RESULTS选项 的作用原理和使用方法
- Django框架效率问题的解决方法和总…
- 打乱数组顺序的三种方法