程式語言Pascal之父Niklaus Wirth曾經說過 :「Algorithms + Data Structures = Programs」。倘若程式是由演算法及資料結構所組成的,那麼設計程式的活動,似乎也應當是由演算法、資料結構的設計及運用所支配。

教科書所介紹的演算法,都有現成的程式實作
許多程式人都曾修習過「資料結構」以及「演算法」的課程。但說實話,肯定有一定比例的程式人在離開校園投入職場後,會發現在自己實務的開發經驗中,這兩門課程中的所學,「似乎」都很少發揮作用。

我相信,對很多程式人來說,心中難免存著疑惑:許多人都說這兩件事情對程式設計來說十分的關鍵,那為什麼在自己實務的開發經驗中,很少感受到它們的重要性呢?

可是,會不會也時常聽到別人說:倘若你不懂資料結構,甚至是演算法,那麼你不過只是一個撰寫程式碼的「工人」,無法成為有價值的程式人?對此,你是否曾經感覺到憂心或是迷惑呢?

事實上,隨著電腦科學的發展,許多有用的資料結構及演算法,早已發展到十分成熟的境界。同時,這些資料結構以及演算法,也已經受到廣泛地實作,並且包裝成為各種很高階的形式(對程式人來說)。

在學校修讀資料結構及演算法課程時,教科書也許花相當多的篇幅討論排序演算法,你會學到Bubble Sort、Insertion Sort、Merge Sort、Quick Sort……等排序的演算法。但當你投入程式設計工作時,會發現教科書所介紹的演算法都有現成的程式庫提供實作,例如C語言的標準函式庫中的qsort()函式,即是提供Quick Sort演算法的函式。對開發工作來說,需要另行設計獨有的排序演算法,機會實在是微乎其微。

即使是大師,也未必設計新的演算法
談到排序,來看看值得一提的例子吧!Java標準程式庫中,有個叫做java.util.Arrays的類別,提供一系列重載版本的sort()函式,允許程式人對各式型別的物件陣列排序,甚至物件在排序時的比較方式也允許自訂,是個相當通用且威力十足的排序函式。

你也可以和我一樣翻開手邊的JDK原始碼。我手邊這個類別的.java檔原始碼版本是1.59,掛名作者的正是2006年造訪臺灣、現正任職Google的兩位大師--Josh Bloch及Neal Gafter。

如果你找出sort()函式的說明,原始碼中明白地指出,這個排序演算法是採用一篇標題為 《Engineering a Sort Function》的論文中所提出,而且是一套經調適後更為快速的Quick Sort演算法。如果你更進一步檢視,會發現當欲排序的元素個數小於7時,它便不再使用Quick Sort,而是採用Insertion Sort。

即使是這兩位卓越的大師,在他們實作排序的功能時,也沒有自行設計新的演算法,而是採用前人所發展的演算法。這無損兩位大師的價值。這個演算法並不是出自於一般教科書中所介紹的演算法,而是出自學術期刊上所發表的論文。

即使你熟讀教科書中的Quick Sort,也不見得能開發出如此快速的排序函式。而且,在Java標準程式庫的這個實作中,這麼做更兼顧實務的考量,因為在元素個數很少時,時間複雜度為n^2的Insertion Sort,實際執行速度還勝過號稱平均會有n*log(n)的Quick Sort。

演算法的實作垂手可得
對現在的程式人來說,演算法的影子在設計工作中之所以越來越淡,有一個核心的原因:我們所需要的絕大多數演算法,早已在層層的分工下發展得十分完備。有人發展原始的演算法、有人持續地進一步改進、有人找到實務上調校的技巧、有人以高階的形式包裝,最終成了可供個人端程式人直接運用的產物。於是,到了程式人手上,只需要呼叫Arrays.sort(),排序問題就由「神燈冒出來的巨人」解決了。

排序演算法只是一個例子,但不可否認的,這數十年,整個電腦科學學術界的研究成果,早已將能滿足我們需求的各種演算法和資料結構,以相當高階的形式包裝起來。對程式人來說,垂手可得。

這使得程式人即使完全不懂這些演算法及資料結構的細部運作,仍然有可能如魚得水地加以操控。事實上,不僅是演算法領域如此,整個電腦科學領域的研究成果,皆在此類層層的分工下,為程式人提供既高階且便利的工具。

所以,你或許會留意到,現今的程式人似乎更重視在演算法及資料結構以外的東西,例如架構上的「設計」。這設計並非演算法或資料結構的規畫及設計,而是規畫、安置軟體建構區塊之間的連結及關係。

程式人將重心轉移到更有生產力地裝配組件
從演算法、資料結構出發的程式設計觀點,這種眼光往往放在如何讓計算機器以高執行效率、節省資源的方式來解決特定的問題。但從架構觀點出發的程式設計觀點,著重的是如何以彈性、容易擴充、容易改變的方式,迅速組裝、搭配各種建構區塊,並從中獲取最大的生產力。

這兩種程式設計的觀點,呈現出截然不同的面貌,也時常惹來喋喋不休的爭論。從演算觀點來看程式設計的人,會認為不懂演算法、或不知如何設計演算法的程式人,設計不出高效、節省資源的程式,所以自然缺乏價值。著重架構觀點的人,則認為許多擅長解題的人、不擅長設計出架構上具有優勢的程式碼。

這中間的認知衝突,乃是源自於程式設計本身具有多面向的特質,因為程式設計既有演算的面向,也同樣具有架構的面向。程式設計也因這多面向的特質,造成了盲人摸象的情況。站在演算觀點的人說,程式設計就是演算法加上資料結構,而立足於架構觀點則說,程式設計與建造建築物差可比擬。對同樣的一項活動,竟然會有差別這麼大的描述方式。

早期對程式設計的活動,偏重在解決特定的問題。這是因為早期對電腦程式的需求,皆起因於想要解決特定的演算問題。設計者可能希望計算給定一組城市以及城市間的距離,計算出任兩個城市之間的最短距離,於是我們有了最短路徑的問題。隨著各式演算問題被探索、研究。這些資產逐漸地累積,便成了現今程式人得以垂手便取的現成產物。這些產物不僅現成,而且還不容易被超越。

當程式人越來越不需要自行開發與實作解決各式特定問題的程式碼時,手上有的便是許許多多的建構組件,而這些組件的來源,正是以多年的研究探討為基礎,再加上軟體產業的層層分工而來的。

能解決問題的組件多半毋需重新再造輪子,況且自己再造的輪子,其品質也難以和現成輪子匹敵。那麼很自然的,程式人便會將重心逐漸轉移,例如更關切如何更有生產力地裝配這些組件。

這些組件對程式人來說,都像是完全不透明的黑盒子,毋需理會內部實作,只需要從抽象高階的觀點理解這些組件,並妥善加以運用即可。一時之間,看似架構觀點所重視的,它們的重要性又凌駕於演算觀點所重視的。

作者簡介:
王建興
清華大學資訊工程系的博士研究生,研究興趣包括電腦網路、點對點網路、分散式網路管理、以及行動式代理人,專長則是Internet應用系統的開發。曾參與過的開發專案性質十分廣泛而且不同,從ERP、PC Game到P2P網路電話都在他的涉獵範圍之內。

熱門新聞

Advertisement