如何从零开始进行程序设计

时间:2025-01-13 作者:Jiaqi Z.

分类:机器学习与人工智能


这一篇虽说是放在机器学习分类下,主要是为课题组内的同学所准备的,但这篇文章所说的一些想法,可能也适用于大多数程序设计的过程(无论是在科研过程中需要写程序、或者是做程序设计课程的课程设计等)。

本篇不会讲解具体的程序设计语言,例如Python、C语言等,而是一种通用的思考方法,可以帮助你更快上手进行一个较大的程序设计。

第一步:明确问题与需求

永远不要一开始就敲代码,仔细思考一下:要解决什么问题。大多数编程活动都是任务驱动或者问题驱动。例如,对于在校大学生而言,写程序可能是为了解决课本上的一个问题,或者老师的一个任务需求,又或者是论文上需要的一部分;对于软件工程师而言,写程序可能是为了实现产品经理的一个特定的需求,或者修复用户提出的一个bug等。盲目开始写程序,总是不可取的。

同时,在明确问题与需求之后,需要考虑的是:这段代码应该使用什么程序语言设计?例如,如果你是希望做机器学习与神经网络相关的,显然Python是更适合的;而像物理专业的一些理论计算,比如解方程等任务,可能使用MATLAB或者Wolfram Mathematica更方便;如果你是做嵌入式单片机的,那几乎就是C语言设计的……总而言之,选择一个合适的程序语言可能会让你的程序设计过程事半功倍。

如果你确实不知道该用什么编程语言的话,试试Python吧

第二步:拆分任务

程序设计的思维一定是模块化的思维,如果一个程序很小,例如判断一个数字是不是质数、或者使用欧几里得算法判断两个数字的最大公因数 等,只需要完成这一个任务就足够了。但通常情况下,使用程序解决的问题往往会很复杂,可能需要多个模块相互配合。这就如同一个公司要进行经营,需要各个部门的配合,其中每个部门都负责自己的内容,最后将其整合起来成为一个完整的公司架构一样。写程序的时候,也应当将任务进行拆分,拆分成一系列的“小任务”(也可以看作模块)。这个模块的大小可以因人而异(或者在具体的软件开发中,可能开发组内又有另外的分工),对于初学者而言,可能程序算法不是太熟练,此时可以将模块尽可能的小。例如,现在希望制作一个值日表安排程序,将一个时间段按照日期,每隔一定天数安排一个人,一共有6个人,按照顺序依次分配。此时我们的程序可能会拆分成这样几个任务:

生成日期-按照一定间隔取出日期-按照顺序安排6个人

注意:这些任务的划分是取决于程序设计者本人的(或者取决于项目开发组的)。

第三步:对每个任务进行拆分,设计步骤

有了具体的任务之后,我们就可以“逐一攻破”了。在程序设计的过程中,我们需要对每个任务进行进一步划分,将其划分为有限次数步骤(这就是算法),这些步骤应当是确定的。例如,在上面的例子中,我们可能需要做这样几个算法(这些算法的每一步并不一定是一行代码,可能是多行代码,甚至有些步骤本身可能足够复杂到成为一个“任务”了)

  1. 读取起始日期和结束日期(yyyy1-mm1-dd1和yyyy2-mm2-dd2)
  2. 定义一个空的列表dates(这个列表是广义上的列表,它可能是C语言中的数组,也可能是MATLAB等程序中的向量,也可能是Python中的列表)
  3. 定义i←0
  4. dates[i]←yyyy1-mm1-dd1(这里面的是一个比较常见的算法符号,表示将右面的值赋值给左边的变量
  5. i←i+1
  6. 查看yyyy1-mm1-dd1+1(表示“下一天”)是否“小于等于”yyyy2-mm2-dd2,如果是,则进行第7步,否则进行第9步
  7. yyyy1-mm1-dd1←yyyy1-mm1-dd1+1
  8. 返回第4步
  9. 输出dates列表

可以注意到,以Python为例,像第2步,第3步这些都是可以用一行表达式如dates=[]i=0进行表示;但类似于第6步,查看某一天的下一天并不是一件“易事”(因为它涉及到一个月的最后一天的判断,甚至可能包括平年闰年的判断等),同时判断一天是否“小于”另一天也不是单纯的比较大小(可能需要三个数的比较),因此,我们可能会把第6步作为一个函数处理(完全可以把“函数”也看作是一种“任务”,但为了与前面的任务区分,我们这里使用“函数”,从程序设计的角度看,函数里面调用函数本身就是合理的

第四步:从底层开始编写代码

这一步难度应该是“最低”的,因为它实际上就是用计算机语言把你前面所想的步骤表示出来。但是,在写代码的时候,有一些小技巧可以注意:

  1. 善用测试:任何人都不敢说可以一次写出正确的程序,大多数时间应当是调试、修改代码。因此,发现程序报错并不可怕,重要的是如何找到错误的地方。如果是一次性写完再测试,那工作量太大,且错误的可能性太大,因此,我们可以每写完一个任务或者一个函数,就测试一下函数的准确性。在测试的时候,可以在程序中以变量赋值的方式给定一些测试数据,或者使用像Python的input()函数,以及C语言的scanf()等方式进行终端的输入(通常直接变量赋值是最方便的)。在输出时可以简单的终端输出,或者根据需要选择像文件输出等方式来判断输出格式的正确性。通常,在涉及底层算法时,其测试可以简单的终端输入输出;而涉及到交互时,可能会需要一些其他的方式(有时这可能需要前后端的配合,但从程序设计“哲学”的角度来看,前后端分离是必需的。)

还是以上面的例子为例,假设我们现在完成了函数addDate(date)函数,给定date函数返回它的下一天。在测试时,我们可以仅仅调用这个函数,给定几个特殊的date(例如,2024年2月28日、2025年2月28日、2023年5月30日、2025年1月8日、2024年12月31日等,可以看到,这里面包含了一个月最后一天,一年最后一天,平年闰年2月的判断,以及常规的日期),通过这几个测试例,可以很容易判断这个函数是否实现的预期的功能。如果测试通过了,可以想见,它在后面的程序中大概率也是正确的,如果测试不通过,一个函数的代码量也是比较小的,容易发现其中的错误。

以我个人的习惯为例,在完成一个函数时,我喜欢对其进行一个小的测试,判断它的功能是否正确;在完成一个大的任务时,我喜欢对其进行一个测试,判断它是否可以正确完成这个任务;在整个程序完成后,再对其进行测试,通常这时候就是判断各个任务之间的“衔接”是否合理。一个需要记住的是:越在早期排查出错误,越能避免后期造成更大更隐蔽的错误

  1. 善用AI:现在的程序设计,几乎AI是不可避免的。我也不反对程序设计中使用AI来生成一些代码。但是,需要特别注意的是:最多使用AI生成一个函数,千万不要使用AI生成一个“任务”,甚至整个程序,AI还没有那么强大,大概率会失控。此时出现的错误,非常难以排查。使用AI生成一个函数,甚至10行左右的语句实现一个功能,如果出现错误,人为排查是很方便的(详见第1条的善用测试

  2. 平地起高楼,地基要打好:还是要本着底层设计的思路,千万不要想着“一口吃成个胖子”,再天才的程序员也做不到一次性写出上千行代码。慢慢来,一步一步来,从简单的开始像“搭积木”一样,最终实现复杂的功能不是难事。而且,不要羡慕别人能写几千、几万行代码,再复杂的代码也是由若干个功能实现的,可能每一个功能也就几十行代码。利用上面的方法,你也可以写出上千上万行代码。

  3. 一定要写注释!:把每一个函数做了什么,每一部分干了什么记录下来,在后期进行整合时会很容易(要不然你一定会“眼花缭乱”的)


上一篇:双曲型、抛物型和椭圆型偏微分方程的区别
下一篇:【快报】从刘谦魔术看排列组合与冒泡算法

同分类上一篇:没有了
同分类下一篇:没有了