如何讀懂一段代碼

對於一段不知道背景知識的代碼,如何讀懂?
對於程序員來說,讀代碼要比寫代碼困難。因爲寫代碼是在自己的世界創造,而讀代碼卻是在接觸別人的世界的建築。每個人的世界都是不盡相同的,因此在讀別人的代碼時,總會有些滯澀,我也是更願意自己寫,讀懂算法思想、梗概,然後自己來實現。因此在過去很長一段時間,寫的代碼都只是一時之快,很難長久——寫完不久之後,我已經不認識自己曾經寫的東西了,甚至覺得那是別人寫的。
要學會寫,先學會讀。
讀別人的代碼,就是走出自己的舒適區,挑戰自己的理解力,開闊自己的思維。同時,在讀的過程中會意識到怎樣的代碼才更容易讓人理解。
今天讀到的一段如下(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就可以。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章