如何读懂一段代码

随笔 专栏收录该内容
17 篇文章 0 订阅

对于一段不知道背景知识的代码,如何读懂?
对于程序员来说,读代码要比写代码困难。因为写代码是在自己的世界创造,而读代码却是在接触别人的世界的建筑。每个人的世界都是不尽相同的,因此在读别人的代码时,总会有些滞涩,我也是更愿意自己写,读懂算法思想、梗概,然后自己来实现。因此在过去很长一段时间,写的代码都只是一时之快,很难长久——写完不久之后,我已经不认识自己曾经写的东西了,甚至觉得那是别人写的。
要学会写,先学会读。
读别人的代码,就是走出自己的舒适区,挑战自己的理解力,开阔自己的思维。同时,在读的过程中会意识到怎样的代码才更容易让人理解。
今天读到的一段如下(Matlab代码,不是很熟悉语法):

   for i = 2:n
        p(i) = inf;
        s(i) = i;
    end  %用Ford 算法求最短路, 赋初值

    for k = 1 : n   %求有向赋权图中源点vs到汇点vt的最短路
        pd = 1; 
        for i = 2 : n
            for j = 1 : n
                if (p(i) > p(j) + a(j,i))
                    p(i) = p(j) + a(j,i);
                    s(i) = j;  %s(i)为点i的标号,表示在最短路径中i点的前一个点的编号
                    pd = 0;
                end;
            end;
        end
        if (pd)
            break;
        end;
    end %求最短路的Ford 算法结束

第一步,先读最简单的——注释。最容易被看懂的注释应该解释的是读者最想知道的内容:这段代码什么意思?但注释不能写那么详细,要尽量写得简洁,所以应该注释的是:这段代码是来做什么的。
这里用名词简洁介绍:Ford算法,作用:求最短路径。那么就知道这段代码是用来求最短路径的,但这还不够。
第二步,读结构。程序的基本结构:顺序、循环、条件分支是大部分程序代码所共有的。这个程序的第一层有顺序的两个结构:循环、循环。第一个循环是顺序语句;第二个循环内含一个两层循环和一个条件语句,两层循环内是一个条件语句。
这步看似复杂,其实熟悉语法的可以很快过掉,即使不熟悉语法,也可以半猜半查的读懂结构,这一步是为后面了解程序所做的数据操作做准备。
第三步,读变量。由于Matlab中的变量是弱类型的,风格不好的代码很难找到其声明或定义,变量往往是拿来就用,因此需要以关键词的形式来分类理解。
这个程序中,有如下关键词是已知显示定义了的:p、s、pd;有如下关键词是未知的(来自于前文或者全局):a;有如下关键词是用于循环变量的:k,i,j。列举如下:
p:初始化为(0,inf,inf….) 长度n
s:初始化为(0,2,3,4…)长度n
pd:初始化为1
a:已知为一个矩阵形式的变量
k:范围1到n
i:范围2到n
j:范围1到n
第四步,结合变量和结构,读数据的操作。
程序的难点在于三层循环。最外层的终止条件除了变量k到n还有pd!=0;第二层无其他条件;最内层有一个条件语句,条件达成则使pd=0,说明多重循环中,若内两层共(n-1)*n次判断均未进入条件则退出最外循环。
基本循环结构已经明了,最关键的是其内部的条件语句以及执行的内容:
条件:p(i) > p(j) + a(j,i)
执行:p(i) = p(j) + a(j,i); s(i) = j;
这里有注释: “s(i)为点i的标号,表示在最短路径中i点的前一个点的编号”
条件中的p(i),i是从2到n,p(j),j是从1到n,最初p(i)都是inf(无穷),因此第一轮是将p(i)赋值为p(j)+a(j,i),这里可以将a(j,i)看作j->i,当做j到i的连接量。第二轮、第三轮,就是对当前的赋值量进行更新,试图找到更小的连接量。
注释最开始就说了,这是找最短路径,便可以理解:这里是在循环中求出p(i)的最小值,p(i)最终就是s(i)->i的连接量,也就是最短的路径权值。
数据的操作归结如下:
操作次数最大为n*n*(n-1),每一次进行判断,s(i)->i,也就是当前这个连接量是不是比s(j)->j、j->i这个量更大,是则更新。循环直到无可更新。

这应该就是Ford算法的描述,通常我们喜欢根据这个描述来写程序,但逆向的过程却很难受,很困难,但这样逆向才能认识到自己写的代码的可读性存在的问题。比如变量的使用,对于ijk这种烂大街的变量由于是循环变量无可厚非,但是p、a、pd的使用却是让人摸不着头脑。对于这类变量的命名,我们应该使用更有意义的命名,不要嫌麻烦(否则让读的人很麻烦),对于弱类型语言,尽可能在命名中表现出类型,比如这里的a命名成mat_connect就可以。

  • 5
    点赞
  • 0
    评论
  • 15
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

君浪

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值