什么是良好的程序设计风格

什么是良好的程序设计风格,第1张

良好的程序设计风格

全局变量用具有描述意义的名字,局部变量用短名字。函数采用动作性的名字。保持一致性。

缩进形式显示程序结构,使用一致的缩行和加括号风格。使用空行显示模块

充分而合理地使用程序注释 给函数和全局数据加注释。不要注释不好的代码,应该重写。不要与代码矛盾。

友好的程序界面,程序界面的方便性及有效性

不要滥用语言技巧 使用表达式的自然形式。利用括号排除歧义。分解复杂的表达式。当心副作用,像++ 这一类运算符具有副作用。

程序的健壮性:容错

模块化编程

1)应该特别注意程序的书写格式,让它的形式反映出其内在的意义结构。

程序是最复杂的东西(虽然你开始写的程序很简单,但它们会逐渐变得复杂起来),是需要用智力去把握的智力产品。良好的格式能使程序结构一目了然,帮助你和别人理解它,帮助你的思维,也帮助你发现程序中不正常的地方,使程序中的错误更容易被发现。

人们常用的格式形式是:逻辑上属于同一个层次的互相对齐;逻辑上属于内部层次的推到下一个对齐位置。请参考本课程的教科书或《C程序设计语言》(The C Programming Language,Brian W Kernighan & Dennis M Rirchie,清华大学出版社,大学计算机教育丛书(影印版,英文),1996。)

利用集成开发环境(IDE)或者其他程序编辑器的功能,可以很方便地维护好程序的良好格式。请注意下面这几个键,在写程序中应该经常用到它们:Enter键(换一行),Tab键(将输入光标移到下一个对齐位置——进入新的一个层次),Backspace键(回到前一个对齐位置——退到外面的一个层次)。

--------------------------------------------------------------------------------

2)用最规范的、最清晰的、最容易理解的方式写程序。注意人们在用C语言写程序的习惯写法,例如教科书中解决类似问题时所使用的写法,《C程序设计语言》一书中有许多极好的程序实例。在这里有一个关于程序模式的相关网页,里面也列出了一些常用的模式。

C语言是一个非常灵活的语言,你可能在这里用许多非常隐晦的方式写程序,但这样写出的程序只能是作为一种玩意儿,就像谜语或者智力游戏。这些东西可以用于消磨时间,但通常与实际无缘。在我们的C语言讨论组里提到过这种东西。

--------------------------------------------------------------------------------

3)在编程中,应仔细研究编译程序给出的错误信息和警告信息,弄清楚每条信息的确切根源并予以解决。特别是,不要忽略那些警告信息,许多警告信息源自隐含的严重错误。我们有许多办法去欺骗编译程序,使它不能发现我们程序中的错误,但这样做最终受到伤害的只能是自己。

--------------------------------------------------------------------------------

4)随时注意表达式计算过程和类型。注意运算符的优先级和结合顺序,不同类型的运算对象将怎样转换,运算的结果是什么类型的,等等。在必要的时候加上括号或显式的类型强制转换。

C语言的运算符很多,优先级定义也不尽合理,很难完全记清楚,因此要特别注意。需要时查一查(不要怕麻烦,相关网页有运算符表),或者直接按照自己的需要加上几个括号。

--------------------------------------------------------------------------------

5)绝不去写依赖于运算对象求值顺序的表达式。对于普通二元运算符的运算对象,函数调用的各个实际参数,C语言都没有规定特定求值顺序。因此,我们不应该写那种依赖于特定求值顺序的表达式,因为不能保证它一定得到什么结果。例如下面的表达式和函数调用都是不合适的,很可能产生你预料不到的结果:

scanf("%d %d", i++, a[i]);

m = n n++;

--------------------------------------------------------------------------------

6)总保证一个函数的定义点和它的所有使用点都能看到同一个完整的函数原型说明。参看《从问题到程序》第103-107页。

--------------------------------------------------------------------------------

7)总注意检查数组的界限和字符串(也以数组的方式存放)的结束。C语言内部根本不检查数组下标表达式的取值是否在合法范围内,也不检查指向数组元素的指针是不是移出了数组的合法区域。写程序的人需要自己保证对数组使用的合法性。越界访问可能造成灾难性的后果。

例:在写处理数组的函数时一般应该有一个范围参数;处理字符串时总检查是否遇到空字符'\0'。

--------------------------------------------------------------------------------

8)绝不对空指针或者悬空的指针做间接访问。这种访问的后果不可预料,可能造成系统的破坏,也可能造成 *** 作系统发现这个程序执行非法 *** 作而强制将它终止。

--------------------------------------------------------------------------------

9)对于所有通过返回值报告运行情况或者出错信息的库函数,都应该检查其执行是否正常完成。如果库函数没有完成 *** 作(可能因为各种原因),随后的 *** 作有可能就是非法的。这种错误也可能在程序运行中隐藏很长时间,到很后来才暴露出来,检查错误非常困难。

--------------------------------------------------------------------------------

10)在带参数宏的定义字符串中,一般应该给整个字符串和其中出现的每个参数都加括号。

C语言预处理程序是个简单的文本替换程序,它根本不知道C语言的语法结构、优先级规则等。不写括号有时会产生我们不希望的代换结果。

--------------------------------------------------------------------------------

11)所有外部变量名字、所有函数名字,应该只靠前6个字符就能够互相区分。因为有些老的编译程序只关注这些名字的前6个字符。如果不注意这个问题,就可能引起隐含的连接错误。

长=编辑框1内容,编辑框1内容是文本型数据,同样编辑框2的内容也是文本型,而你的局部变量全部是整数型数据

正确写法:

程序集 窗口程序集1

子程序 _按钮1_被单击

局部变量 周长, 整数型

局部变量 面积, 整数型

局部变量 宽, 整数型

局部变量 长, 整数型

长 = 到整数( 编辑框1内容)

宽 = 到整数( 编辑框2内容)

周长 = (长 + 宽) × 2

编辑框3内容=到文本(周长)

贪心是人类自带的能力,贪心算法是在贪心决策上进行统筹规划的统称。

比如一道常见的算法笔试题---- 跳一跳

我们自然而然能产生一种解法:尽可能的往右跳,看最后是否能到达。

本文即是对这种贪心决策的介绍。

狭义的贪心算法指的是解最优化问题的一种特殊方法,解决过程中总是做出当下最好的选择,因为具有最优子结构的特点,局部最优解可以得到全局最优解;这种贪心算法是动态规划的一种特例。 能用贪心解决的问题,也可以用动态规划解决。

而广义的贪心指的是一种通用的贪心策略,基于当前局面而进行贪心决策。以 跳一跳 的题目为例:

我们发现的题目的核心在于 向右能到达的最远距离 ,我们用maxRight来表示;

此时有一种贪心的策略:从第1个盒子开始向右遍历,对于每个经过的盒子,不断更新maxRight的值。

贪心的思考过程类似动态规划,依旧是两步: 大事化小 小事化了

大事化小:

一个较大的问题,通过找到与子问题的重叠,把复杂的问题划分为多个小问题;

小事化了:

从小问题找到决策的核心,确定一种得到最优解的策略,比如跳一跳中的 向右能到达的最远距离

在证明局部的最优解是否可以推出全局最优解的时候,常会用到数学的证明方式。

如果是动态规划:

要凑出m元,必须先凑出m-1、m-2、m-5、m-10元,我们用dp[i]表示凑出i元的最少纸币数;

有 dp[i]=min(dp[i-1], dp[i-2], dp[i-5], dp[i-10]) + 1 ;

容易知道 dp[1]=dp[2]=dp[5]=dp[10]=1 ;

根据以上递推方程和初始化信息,可以容易推出dp[1~m]的所有值。

似乎有些不对? 平时我们找零钱有这么复杂吗?

从贪心算法角度出发,当m>10且我们有10元纸币,我们优先使用10元纸币,然后再是5元、2元、1元纸币。

从日常生活的经验知道,这么做是正确的,但是为什么?

假如我们把题目变成这样,原来的策略还能生效吗?

接下来我们来分析这种策略:

已知对于m元纸币,1,2,5元纸币使用了a,b,c张,我们有a+2b+5c=m;

假设存在一种情况,1、2、5元纸币使用数是x,y,z张,使用了更少的5元纸币(z<c),且纸币张数更少(x+y+z<a+b+c),即是用更少5元纸币得到最优解。

我们令k=5(c-z),k元纸币需要floor(k/2)张2元纸币,k%2张1元纸币;(因为如果有2张1元纸币,可以使用1张2元纸币来替代,故而1元纸币只能是0张或者1张)

容易知道,减少(c-z)张5元纸币,需要增加floor(5(c-z)/2)张2元纸币和(5(c-z))%2张纸币,而这使得x+y+z必然大于a+b+c。

由此我们知道不可能存在使用更少5元纸币的更优解。

所以优先使用大额纸币是一种正确的贪心选择。

对于1、5、7元纸币,比如说要凑出10元,如果优先使用7元纸币,则张数是4;(1+1+1+7)

但如果只使用5元纸币,则张数是2;(5+5)

在这种情况下,优先使用大额纸币是不正确的贪心选择。(但用动态规划仍能得到最优解)

如果是动态规划:

前i秒的完成的任务数,可以由前面1~i-1秒的任务完成数推过来。

我们用 dp[i]表示前i秒能完成的任务数

在计算前i秒能完成的任务数时,对于第j个任务,我们有两种决策:

1、不执行这个任务,那么dp[i]没有变化;

2、执行这个任务,那么必须腾出来(Sj, Tj)这段时间,那么 dp[i] = max(dp[i], dp[ S[j] ] ) + 1 ;

比如说对于任务j如果是第5秒开始第10秒结束,如果i>=10,那么有 dp[i]=max(dp[i], dp[5] + 1); (相当于把第5秒到第i秒的时间分配给任务j)

再考虑贪心的策略,现实生活中人们是如何安排这种多任务的事情?我换一种描述方式:

我们自然而然会想到一个策略: 先把结束时间早的兼职给做了!

为什么?

因为先做完这个结束时间早的,能留出更多的时间做其他兼职。

我们天生具备了这种优化决策的能力。

这是一道 LeetCode题目 。

这个题目不能直接用动态规划去解,比如用dp[i]表示前i个人需要的最少糖果数。

因为(前i个人的最少糖果数)这种状态表示会收到第i+1个人的影响,如果a[i]>a[i+1],那么第i个人应该比第i+1个人多。

即是 这种状态表示不具备无后效性。

如果是我们分配糖果,我们应该怎么分配?

答案是: 从分数最低的开始。

按照分数排序,从最低开始分,每次判断是否比左右的分数高。

假设每个人分c[i]个糖果,那么对于第i个人有 c[i]=max(c[i-1],c[c+1])+1 ; (c[i]默认为0,如果在计算i的时候,c[i-1]为0,表示i-1的分数比i高)

但是,这样解决的时间复杂度为 O(NLogN) ,主要瓶颈是在排序。

如果提交,会得到 Time Limit Exceeded 的提示。

我们需要对贪心的策略进行优化:

我们把左右两种情况分开看。

如果只考虑比左边的人分数高时,容易得到策略:

从左到右遍历,如果a[i]>a[i-1],则有c[i]=c[i-1]+1;否则c[i]=1。

再考虑比右边的人分数高时,此时我们要从数组的最右边,向左开始遍历:

如果a[i]>a[i+1], 则有c[i]=c[i+1]+1;否则c[i]不变;

这样讲过两次遍历,我们可以得到一个分配方案,并且时间复杂度是 O(N)

题目给出关键信息:1、两个人过河,耗时为较长的时间;

还有隐藏的信息:2、两个人过河后,需要有一个人把船开回去;

要保证总时间尽可能小,这里有两个关键原则: 应该使得两个人时间差尽可能小(减少浪费),同时船回去的时间也尽可能小(减少等待)。

先不考虑空船回来的情况,如果有无限多的船,那么应该怎么分配?

答案: 每次从剩下的人选择耗时最长的人,再选择与他耗时最接近的人。

再考虑只有一条船的情况,假设有A/B/C三个人,并且耗时A<B<C。

那么最快的方案是:A+B去, A回;A+C去;总耗时是A+B+C。(因为A是最快的,让其他人来回时间只会更长, 减少等待的原则

如果有A/B/C/D四个人,且耗时A<B<C<D,这时有两种方案:

1、最快的来回送人方式,A+B去;A回;A+C去,A回;A+D去; 总耗时是B+C+D+2A (减少等待原则)

2、最快和次快一起送人方式,A+B先去,A回;C+D去,B回;A+B去;总耗时是 3B+D+A (减少浪费原则)

对比方案1、2的选择,我们发现差别仅在A+C和2B;

为何方案1、2差别里没有D?

因为D最终一定要过河,且耗时一定为D。

如果有A/B/C/D/E 5个人,且耗时A<B<C<D<E,这时如何抉择?

仍是从最慢的E看。(参考我们无限多船的情况)

方案1,减少等待;先送E过去,然后接着考虑四个人的情况;

方案2,减少浪费;先送E/D过去,然后接着考虑A/B/C三个人的情况;(4人的时候的方案2)

到5个人的时候,我们已经明显发了一个特点:问题是重复,且可以由子问题去解决。

根据5个人的情况,我们可以推出状态转移方程 dp[i] = min(dp[i - 1] + a[i] + a[1], dp[i - 2] + a[2] + a[1] + a[i] + a[2]);

再根据我们考虑的1、2、3、4个人的情况,我们分别可以算出dp[i]的初始化值:

dp[1] = a[1];

dp[2] = a[2];

dp[3] = a[2]+a[1]+a[3];

dp[4] = min(dp[3] + a[4] + a[1], dp[2]+a[2]+a[1]+a[4]+a[2]);

由上述的状态转移方程和初始化值,我们可以推出dp[n]的值。

贪心的学习过程,就是对自己的思考进行优化。

是把握已有信息,进行最优化决策。

这里还有一些收集的 贪心练习题 ,可以实践练习。

这里 还有在线分享,欢迎报名。

以上就是关于什么是良好的程序设计风格全部的内容,包括:什么是良好的程序设计风格、易语言10044错误、程序员算法基础——贪心算法等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/10219474.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-06
下一篇 2023-05-06

发表评论

登录后才能评论

评论列表(0条)

保存