当前位置:首页 > 休闲

《普林斯頓最熱門的電腦通識課》:「二分搜尋演算法」的重點是,需要執行的工作量與資料量成正比

文:布萊恩・柯尼罕(Brian W. Kernighan)

線性演算法

設若我們想知道這房間中最高的普林人是誰,我們只需環顧一下,斯頓搜尋做個猜測,最熱重點資料正比但一個演算法必須非常精確詳盡地說明所有步驟,電腦精確到就連一台很笨的通識電腦都能循著這些步驟去執行。基本方法是課分逐一詢問每一個人的身高,記錄截至目前為止最高的演算那個人。所以,需執行我們可能逐一詢問每個人:「約翰,工作你多高?瑪麗,量與量成妳多高?」等等。普林

若約翰是斯頓搜尋我們第一個詢問的人,那麼,最熱重點資料正比截至目前為止,電腦他是通識最高的人;若瑪麗更高,她現在就是最高的人,否則,約翰仍是截至目前為止最高的人。接著,我們詢問第三個人。這流程結束時——詢問完每個人後,我們就知道誰是最高的人,以及他(她)的身高。我們也可以用這方法去找出最有錢的人,或姓氏在字母排序中最前面的人,或生日最接近年底的人。

這其中也涉及複雜情況。我們該如何處理重複的情形,例如,有二或更多人的身高相同時?碰上這種情況,我們必須選擇報告這其中的第一個人,或最後一個人,或隨機選一個,或他們所有人。若我們要找出最大一組中身高相同者,這是明顯較難的問題,因為這意味的是,我們必須記住所有身高相同者的姓名:這必須直到問完名單上的最後一人時,我們才能得知。這個例子涉及資料結構(data structures)——如何表述一個運算中所需的資訊,這是許多演算法的一個重要考量,但我們將不會在此對它們多做討論。

若我們想計算平均身高呢?我們可以詢問每個人的身高,在取得這些數值時,把它們加起來(或許可以使用Toy程式去加總一連串的數字),最後,把總和除以人數。若一張紙上寫了N個身高,我們可以用以下更「演算性」的方式來表達這個例子:

圖片_1

但若我們要一台電腦去做這工作,就必須更加小心。例如,若這張紙上沒有數字呢?若這工作是由人去執行,不會有何問題,因為我們知道,若紙上沒有任何數字的話,就啥事都不必做。但若由一台電腦做這工作,就必須告訴電腦去檢查這可能性,並且告訴它,若發生沒有數字的情況,它該如何反應。

若未告訴電腦去檢查這可能性,當發生沒有數字的情況時,電腦就會去把總和除以0,這是一個未定義的運算。演算法及電腦必須處理所有可能的情況,若你曾經收到一張上面填寫「0元0角」的支票,或是一張叫你去支付「應付餘額:零」的帳單,這就是沒有正確地檢查所有情況的失敗例子。

若我們事情不知道有多少筆資料項(這是通常的情形)呢?我們可以在運算總和的同時,計數有多少筆資料:

圖片_11

上述指令也處理了被除數為0的潛在問題,它清楚地檢查是否有這種尷尬情況。

演算法的一個重要特性是它們的運算效率——它們的運算快或慢,以及它們花多少時間去處理一定數量的資料?就前述例子來說,執行的步驟數或一台電腦花多少時間做這工作,直接與必須處理的資料量成正比,若房間裡的人數多一倍,就得多花一倍的時間去找出最高的人或計算出平均身高,若有十倍的人,就得花十倍的時間。

當運算時間直接或線性正比於資料量時,這演算法稱為「線性時間演算法」(linear-time algorithm),或簡稱「線性演算法」(linear algorithm)。若我們繪出運算時間和資料量的關係圖,那將是一條從左下往右上延伸的直線。我們日常生活中遇到的許多演算法是線性演算法,因為它們對一些資料執行相同的基本運算,愈多資料意味著愈多工作,兩者成正比(譯註:用線性演算法執行排序工作時,若資料量為N,演算法需要執行的運算次數為N)。

許多線性演算法呈現相同的基本形式:可能有一些初始化,例如把累計總和設定為0,或是把最大身高設定為一個小數值;接著,依序檢查每個資料項,並對它執行一個簡單運算——計數,和前一個值相較,以一個簡單方式交換,或許還加上列印出來;最後,可能需要一個步驟去結束工作,例如運算出平均值,或是把總和或最大身高值列印出來。

若每一筆資料的運算花大約等量時間,忽略電話簿的前半部分,接著查看後半部分的大約中間頁(亦即整個電話簿從最前面算起的約四分之三處)。由於電話簿上的名稱是按照字母順序排列,因此,每一步,我們知道接下來該查看哪一半(前半部分,抑或後半部分),這樣一步步下來,最終得出兩種結果之一:找到我們要查詢的那個名稱,或是確知電話簿上沒有這個名稱。

這種搜尋演算法稱為「二分搜尋演算法」(binary search algorithm),因為每一次的檢查或比較,都會把資料項區分成兩群,其中一群是不必再繼續考慮的資料項,這是一種名為「分治法」(divide and conquer)的策略的一個例子。二分搜尋演算法有多快呢?每一步將把剩餘資料項中的另一半排除,因此,步驟數就是我們可以把原資料數量除以2的次數,直到只剩下一個資料項。

設若我們一開始有1024個姓名(註:選擇這個數字是為了計算和解說的方便),第一次比較,可以排除512個姓名;第二次比較後,剩下256個;接著是128個,接著是64個,接著是32個,接著是16個,8個,4個,2個,最終1個。總計比較了10次,210是1024,這顯然不是巧合,比較次數是2的冪次,得出原始的資料項數量;從1,到2,到4……到1024,每次都是乘以2。


分享到:

京ICP备19007577号-5