1. 程式人生 > >演算法中虛擬碼的書寫學習

演算法中虛擬碼的書寫學習

原文轉載:https://blog.csdn.net/mylinchi/article/details/53558597

        虛擬碼(Pseudocode)是一種演算法描述語言。使用虛擬碼的目的是為了使被描述的演算法可以容易地以任何一種程式語言( Pascal,C,Java,etc)實現。因此,虛擬碼必須結構清晰、程式碼簡單、可讀性好,並且類似自然語言。 介於自然語言與程式語言之間。

  它以程式語言的書寫形式指明演算法的職能。

  當考慮演算法功能(而不是其語言實現)時,虛擬碼常常得到應用。電腦科學在教學中通常使用虛擬碼,以使得所有的程式設計師都能理解。

  綜上,簡單的說,讓人便於理解的程式碼。不依賴於語言的,用來表示程式執行過程,而不一定能編譯執行的程式碼。在資料結構講演算法的時候用的很多。 

語法規則

  例如,類Pascal語言的虛擬碼的語法規則是: 在虛擬碼中,每一條指令佔一行(else if,例外)。指令後不跟任何符號( Pascal和C中語句要以分號結尾)。書寫上的“縮排”表示程式中的分支程式結構。這種縮排風格也適用於if-then-else語句。用縮排取代傳統Pascal中的begin和end語句來表示程式的塊結構可以大大提高程式碼的清晰性;同一模組的語句有相同的縮排量,次一級模組的語句相對與其父級模組的語句縮排。

        演算法的虛擬碼語言在某些方面可能顯得不太正規,但是給我們描述演算法提供了很多方便,並且可以使我們忽略演算法實現中很多麻煩的細節。通常每個演算法開始時都要描述它的輸入和輸出,而且演算法中的每一行都給編上號碼,在解釋演算法的過程中會經常使用演算法步驟中的行號來指代演算法的步驟。演算法的虛擬碼描述形式上並不是非常嚴格,其主要特性和通常的規定如下:
        1) 演算法中出現的陣列、變數可以是以下型別:整數、實數、字元、位串或指標。通常這些型別可以從演算法的上下文來看是清楚的,並不需要額外加以說明。
        2) 在演算法中的某些指令或子任務可以用文字來敘述

,例如,”設x是A中的最大項”,這裡A是一個數組;或者”將x插入L中”,這裡L是一個連結串列。這樣做的目的是為了避免因那些與主要問題無關的細節使演算法本身雜亂無章。
        3) 算術表示式可以使用通常的算術運算子(+,-,*,/,以及表示冪的^)。邏輯表示式可以使用關係運算符=,≠,<,>,≤和≥,以及邏輯運算子與(and),或(or),非(not)。
        4) 賦值語句是如下形式的語句:a<-b 。這裡a是變數、陣列項,b是算術表示式、邏輯表示式或指標表示式。語句的含義是將b的值賦給a。
        5) 若a和b都是變數、陣列項,那麼記號a<->b 表示a和b的內容進行交換。
        6) goto語句具有形式   goto label(goto標號)它將導致轉向具有指定標號的語句。
        7) 條件語句有以下兩種形式:
                                            if c then s或者 
                                               if c then s
                                                  else s′
這裡c是邏輯表示式,s和s′是單一的語句或者是被括在do和end之間的語句串。對於上述兩種形式,假若c為真,則s被執行一次。假若c為假,則在第一種形式中,if語句的執行就完成了,而在第二種形式中,執行s′。在所有的情況下,控制就進行到了下一個語句,除非在s或s′中的goto語句使控制轉向到其它地方。
         8) 有兩種迴圈指令:while和for。
         while語句的形式是
                                              while c do  
                                                    s
                                                  end
這裡c是邏輯表示式,而s是由一個或更多個語句組成的語句串。當c為真時,執行s。在每一次執行s之前,c都被檢查一下;假若c為假,控制就進行到緊跟在while語句後面的語句。注意,當控制第一次達到while語句時,假若c為假,則s一次也不執行。 
       for語句的形式是
                                      for var init to limit by incr do
                                                        s
                                                      end
這裡var是變數,init、limit和incr都是算術表示式,而s是由一個或多個語句組成的語句串。初始時,var被賦予init的值。假若incr≥0,則只要var≤limit,就執行s並且將incr加到var上。(假若incr<0,則只要var≥limit,就執行s並且將incr加到var上)。incr的符號不能由s來該改變。
      9) exit語句可以在通常的結束條件滿足之前,被用來結束while迴圈或者for迴圈的執行。exit導致轉向到緊接在包含exit的(最內層)while或者for迴圈後面的一個語句。
     10) return用來指出一個演算法執行的終點;如果演算法在最後一條指令之後結束,它通常是被省略的;它被用得最多的場合是檢測到不合需要的條件時。return的後面可以緊接被括在引號的資訊。
      11) 演算法中的註釋被括在/* */之中。諸如read和output之類的各種輸入或者輸出也在需要時被用到。
     

虛擬碼例項

  虛擬碼只是像流程圖一樣用在程式設計的初期,幫助寫出程式流程。簡單的程式一般都不用寫流程、寫思路,但是複雜的程式碼,最好還是把流程寫下來,總體上去考慮整個功能如何實現。寫完以後不僅可以用來作為以後測試,維護的基礎,還可用來與他人交流。但是,如果把全部的東西寫下來必定可能會讓費很多時間,那麼這個時候可以採用虛擬碼方式。比如:

  IF 九點以前 THEN

     do 私人事務;

  ELSE 9點到18點 THEN

  工作;

  ELSE

  下班;

  END IF

  這樣不但可以達到文件的效果,同時可以節約時間. 更重要的是,使結構比較清晰,表達方式更加直觀.

  下面介紹一種類Pascal語言的虛擬碼的語法規則。

  在虛擬碼中,每一條指令佔一行(else if 例外,),指令後不跟任何符號(Pascal和C中語句要以分號結尾);

  書寫上的“縮排”表示程式中的分支程式結構。這種縮排風格也適用於if-then-else語句。用縮排取代傳統Pascal中的begin和end語句來表示程式的塊結構可以大大提高程式碼的清晰性;同一模組的語句有相同的縮排量,次一級模組的語句相對與其父級模組的語句縮排; 

  在虛擬碼中,通常用連續的數字或字母來標示同一即模組中的連續語句,有時也可省略標號。

  符號△後的內容表示註釋;

  在虛擬碼中,變數名和保留字不區分大小寫,這一點和Pascal相同,與C或C++不同;

  在虛擬碼中,變數不需宣告,但變數區域性於特定過程,不能不加顯示的說明就使用全域性變數;

  賦值語句用符號←表示,x←exp表示將exp的值賦給x,其中x是一個變數,exp是一個與x同類型的變數或表示式(該表示式的結果與x同類型);多重賦值i←j←e是將表示式e的值賦給變數i和j,這種表示與j←e和i←e等價。

  例如:

  x←y

  x←20*(y+1)

  x←y←30

  以上語句用C分別表示為:

  x = y;

  x = 20*(y+1);

  x = y = 30;

  選擇語句用if-then-else來表示,並且這種if-then-else可以巢狀,與Pascal中的if-then-else沒有什麼區別。

  例如:

  if (Condition1)

  then [ Block 1 ]

  else if (Condition2)

  then [ Block 2 ]

  else [ Block 3 ]

  迴圈語句有三種:while迴圈、repeat-until迴圈和for迴圈,其語法均與Pascal類似,只是用縮排代替begin - end;

  例如:

  1. x ← 0

  2. y ← 0

  3. z ← 0

  4. while x < N

  1. do x ← x + 1

  2. y ← x + y

  3. for t ← 0 to 10

  1. do z ← ( z + x * y ) / 100

  2. repeat

  1. y ← y + 1

  2. z ← z - y

  3. until z < 0

  4. z ← x * y

  5. y ← y / 2

   上述語句用C或C++來描述是:

  x = y = z = 0;

  while( z < N )

  {

  x ++;

  y += x;

  for( t = 0; t < 10; t++ )

  {

  z = ( z + x * y ) / 100;

  do {

  y ++;

  z -= y;

  } while( z >= 0 );

     }

  z = x * y;

  }

  y /= 2;

  陣列元素的存取有陣列名後跟“[下標]”表示。例如A[j]指示陣列A的第j個元素。符號“ …”用來指示陣列中值的範圍。

  例如:

  A[1…j]表示含元素A[1], A[2], … , A[j]的子陣列;

  複合資料用物件(Object)來表示,物件由屬性(attribute)和域(field)構成。域的存取是由域名後接由方括號括住的物件名錶示。

  例如:

  陣列可被看作是一個物件,其屬性有length,表示其中元素的個數,則length[A]就表示陣列A中的元素的個數。在表示陣列元素和物件屬性時都要用方括號,一般來說從上下文可以看出其含義。

  用於表示一個數組或物件的變數被看作是指向表示陣列或物件的資料的一個指標。對於某個物件x的所有域f,賦值y←x就使f[y]=f[x],更進一步,若有f[x]←3,則不僅有f[x]=3,同時有f[y]=3,換言之,在賦值y←x後,x和y指向同一個物件。

  有時,一個指標不指向任何物件,這時我們賦給他nil。

  函式和過程語法與Pascal類似。

  函式值利用 “return (函式返回值)” 語句來返回,呼叫方法與Pascal類似;過程用 “call 過程名”語句來呼叫;

  例如:

  1. x ← t + 10

  2. y ← sin(x)

  3. call CalValue(x,y)

  引數用按值傳遞方式傳給一個過程:被呼叫過程接受引數的一份副本,若他對某個引數賦值,則這種變化對發出呼叫的過程是不可見的。當傳遞一個物件時,只是拷貝指向該物件的指標,而不拷貝其各個域。