演算法 Algorithm
演算法是在有限步驟內求解某一問題所使用的一組定義明確的規則。通俗點說,就是電腦解題的過程。在這個過程中,無論是形成解題思路還是編寫程式,都是在實施某種演算法。前者是推理實現的演算法,後者是操作實現的演算法。 一個演算法應該具有以下五個重要的特徵: 有窮性: 一個演算法必須保證執行有限步之後結束;確切性: 演算法的每一步驟必須有確切的定義;輸入:一個演算法有0個或多個輸入,以刻畫運算對象的初始情況,所謂0個輸入是指演算法本身定除了初始條件;輸出:一個演算法有一個或多個輸出,以反映對輸入資料加工後的結果。沒有輸出的演算法是毫無意義的;可行性: 演算法原則上能夠精確地運行,而且人們用筆和紙做有限次運算後即可完成。
Did you knowAlgorithm 一詞的由來 Algorithm(演算法)一詞本身就十分有趣。初看起來,這個詞好像是某人打算要寫“Logarithm”(對數)一詞但卻把頭四個字母寫的前後顛倒了。這個詞一直到1957年之前在Webster's New World Dictionary(《韋氏新世界詞典》)中還未出現,我們只能找到帶有它的古代涵義的較老形式的“Algorism”(算術),指的是用阿拉伯數字進行算術運算的過程。在中世紀時,珠算家用算盤進行計算,而算術家用算術進行計算。中世紀之後,對這個詞的起源已經拿不準了,早期的語言學家試圖推斷它的來曆,認為它是從把algiros(費力的)+arithmos(數字)組合起來派生而成的,但另一些人則不同意這種說法,認為這個詞是從“喀斯迪爾國王Algor”派生而來的。最後,數學史學家發現了algorism(算術)一詞的真實起源:它來源於著名的Persian Textbook(《波斯教科書》)的作者的名字Abu Ja'far Mohammed ibn Mûsâ al-Khowârizm (約公元前825年)——從字面上看,這個名字的意思是“Ja'far 的父親,Mohammed 和 Mûsâ 的兒子,Khowârizm 的本地人”。Khowârizm 是前蘇聯XИBA(基發) 的小城鎮 。Al-Khowârizm 寫了著名的書Kitab al jabr w'al-muqabala (《複原和化簡的規則》);另一個詞,“algebra”(代數),是從他的書的標題引出來的,儘管這本書實際上根本不是講代數的。 逐漸地,“algorism”的形式和意義就變得面目全非了。如牛津英語字典所說明的,這個詞是由於同arithmetic(算術)相混淆而形成的錯拼詞。由algorism又變成algorithm。一本早期的德文數學詞典 Vollstandiges Mathematisches Lexicon (《數學大全辭典》) ,給出了Algorithmus (演算法)一詞的如下定義:“在這個名稱之下,組合了四種類型的算術計算的概念,即加法、乘法、減法、除法”。拉頂短語algorithmus infinitesimalis (無限小方法) ,在當時就用來表示Leibnitz(萊布尼茲)所發明的以無限小量進行計算的微積分方法。 1950年左右,algorithm一詞經常地同歐幾裡德演算法(Euclid's algorithm)聯絡在一起。這個演算法就是在歐幾裡德的《幾何原本》(Euclid's Elements ,第VII卷,命題i和ii)中所闡述的求兩個數的最大公約數的過程(即輾轉相除法)。 Abu Ja'far Mohammed ibn Mûsâ al-Khowârizm Born: about 780 in Baghdad (now in Iraq)Died: about 850 ·虛擬碼的使用 Usage of Pseudocode虛擬碼(Pseudocode)是一種演算法描述語言。使用為代碼的目的是為了使被描述的演算法可以容易地以任何一種程式設計語言(Pascal, C, Java, etc)實現。因此,虛擬碼必須結構清晰,代碼簡單,可讀性好,並且類似自然語言。 下面介紹一種類Pascal語言的虛擬碼的文法規則。 虛擬碼的文法規則在虛擬碼中,每一條指令佔一行(else if 例外,),指令後不跟任何符號(Pascal和C中語句要以分號結尾);書寫上的“縮排”表示程式中的分支程式結構。這種縮排風格也適用於if-then-else語句。用縮排取代傳統Pascal中的begin和end語句來表示程式的塊結構可以大大提高代碼的清晰性;同一模組的語句有相同的縮排量,次一級模組的語句相對與其父級模組的語句縮排;例如: line 1 line 2 sub line 1 sub line 2 sub sub line 1 sub sub line 2 sub line 3 line 3 而在Pascal中這種關係用begin和end的嵌套來表示, line 1 line 2 begin sub line 1 sub line 2 begin sub sub line 1 sub sub line 2 end; sub line 3 end; line 3在C中這種關係用{ 和 } 的嵌套來表示, line 1 line 2 { sub line 1 sub line 2 { sub sub line 1 sub sub line 2 } sub line 3 } line 3 在虛擬碼中,通常用連續的數字或字母來標示同一即模組中的連續語句,有時也可省略標號。例如: 1. line 1 2. line 2 a. sub line 1 b. sub line 2 1. sub sub line 1 2. sub sub line 2 c. sub line 3 3. line 3符號△後的內容表示注釋;在虛擬碼中,變數名和保留字不區分大小寫,這一點和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 以上語句用Pascal分別表示為: x := y; x := 20*(y+1); x := 30; 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 上述語句用Pascal來描述是: x := 0; y := 0; z := 0; while x < N do begin x := x + 1; y := x + y; for t := 0 to 10 do begin z := ( z + x * y ) / 100; repeat y := y + 1; z := z - y; until z < 0; end; z := x * y; end; 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) 參數用按值傳遞方式傳給一個過程:被調用過程接受參數的一份副本,若他對某個參數賦值,則這種變化對發出調用的過程是不可見的。當傳遞一個對象時,只是拷貝指向該對象的指標,而不拷貝其各個域。