1. 程式人生 > ><資料結構與演算法分析>讀書筆記--要分析的問題

<資料結構與演算法分析>讀書筆記--要分析的問題

通常,要分析的最重要的資源就是執行時間。有幾個因素影響著程式的執行時間。有些因素(如使用編譯器和計算機)顯然超出了任何理論模型的範疇,因此,雖然它們是重要的,但是我們在這裡還是不能考慮它們。剩下的主要因素是所使用的演算法以及對該演算法的輸入。

典型的情形是,輸入的大小是主要的考慮方面。我們定義兩個函式Tavg(N)和Tworst(N),分別為演算法對於輸入量N所花費的平均執行時間和最壞情況的執行時間。顯然,Tavg(N)<=Tworst(N)。

如果存在多於一個的輸入,那麼這些函式可用有多於一個的變數。

偶爾也分析一個演算法的最好情形的效能。不過,通常這沒有什麼重要意義,因為它不代表典型的行為。平均情形效能常常反映典型的行為,而最壞的效能則代表對任何可能輸入的效能一種保證。還要注意,雖然在這一章我們分析的是Java程式,但所得到的界實際上是演算法的界而不是程式的界。程式是演算法以一種特殊程式語言的實現,程式設計語言的細節幾乎總是不影響大於O的答案。如果一個程式比演算法分析提出的速度慢得多,那麼可能存在低效率的實現。這在類似C++的語言中很普遍,比如,陣列可能當作整體而被漫不經心的拷貝,而不是由引用來傳遞。不管怎麼說,這在Java中也可能出現。

 

一般來說,如果沒有相反的指定,則所需要的量是最壞情況的執行時間。其原因之一是它對所有的輸入提供了一個界限,包括特別壞的輸入,而平均情況分析不提供這樣的界。另一個原因是平均情況的界計算起來通常要困難得多。在某些情況下,“平均”的定義可能影響分析的結果。(例如,什麼是下屬問題的平均輸入?)

作為一個例子,我們將在下一節考慮下述問題:

最大子序列和問題:

例如:對於輸入-2,11,-4,13,-5,-2,答案為20(從A2到A4) 。

這個問題之所以有吸引力,主要是因為存在求解它的很多演算法,而這些演算法的效能又差異很大。我們將討論求解該問題的四種演算法。這四種演算法在某臺計算機上(究竟是哪一臺具體的計算機並不重要)的執行時間。如圖:

 

 

 在表中有幾個重要的情況值得注意。對於小量的輸入,這些演算法都在眨眼之間完成,因此如果只是小量輸入的情形,那麼花費大量的努力去設計聰明的演算法恐怕就太不值得了。

另一方面,近來對於重寫那些不再合理的基於小輸入量假設而在五年以前編寫的程式確實存在巨大的市場。現在看來,這些程式太慢了,因為它們用的是一些低劣的演算法。對於大量的輸入,演算法4顯然是最好的選擇(雖然演算法3也可以用)。

 

其次,表中所給的時間不包括讀入資料所需要的時間。對於演算法4,僅僅從磁碟讀入資料所用的時間很可能在數量級上比求解上述問題所需要的時間還要大。這是許多有效演算法的典型特點。資料的讀入一般是個瓶頸;一旦資料讀入,問題就會迅速解決。但是,對於低效率的演算法情況就不同了,它必然要佔用大量的計算機資源。因此只要可能,使得演算法足夠有效而不至成為問題的瓶頸是非常重要的。

注意到具有線性複雜度的演算法4表現很好,當問題的規模增長了十倍的時候,其執行的時間也增長十倍。而具有平方複雜度的演算法2就不行了,十倍的規模增長導致執行時間大於有百倍(10的2次方)的增長。而立方級複雜度的演算法1的執行時間則由千倍(10的3次方)的增長。對於N=100000,我們可以預期演算法1將花費近乎90000秒或一天的時間。類似地,我們可預期演算法2用大約333秒來完成N=1000000。然而,演算法2也可能花費更多的時間,因為在現代計算機中,記憶體存取N=1000000可能比處理N=100000要慢,這取決於記憶體快取的大小。

再看圖:

 

左圖指出了四種演算法執行時間的增長率。儘管該圖只包含N從10到100的值,但是相對增長率還是很明顯的。雖然O(NlogN)演算法的圖看起來是線性的,但是用直尺的邊(或是一張紙)容易驗證它並不是直線。雖然O(N)演算法的圖看似直線,但這只是因為對於小的N值其中的常數項大於線性項。右圖中更顯示對於更大值的效能。該圖明顯地表明,對於即使是適度大小的輸入量低效演算法依然是多麼的無用。