本翻譯版權所有,轉載請註明:
本章爲Boost Graph Library的在線文檔的第一章(參見http://www.boost.org/doc/libs/1_36_0/libs/graph/doc/table_of_contents.html)。前段時間研究編譯原理中的屬性計算時,看到拓撲排序,突然對Boost中的這個庫有了興趣,就翻譯了這篇簡介。
Boost 圖類庫(BGL)
圖(graph)是一種數學抽象,可用於解決計算機科學領域的多種問題。因此,這種抽象必須也由計算機程序表達出來。一個用於遍歷圖的標準化的範型接口,對於促進對圖算法和數據結構的重用,具有無可比擬的重要性。Boost 圖類庫(BGL)的一部份是一個可用於訪問圖的結構的範型接口,同時隱藏了其實現細節。這是一個開放的接口,這意味着任何實現了該接口的圖類庫,都將可以與BGL範型算法(或是其他使用了該接口的算法)相互協作。BGL提供了一些遵循該接口的通用目的的圖類,但它們並不企圖成爲唯一的圖類;肯定會有其他圖類更適合於特定場合。我們相信,BGL的主要貢獻將是對該接口的規劃。
BGL圖接口和圖組件是範型的(generic),如同標準模板庫(STL)[2]。在下一節中我們將回顧範型編程在STL中扮演的角色,並將其與我們如何在圖的背景下應用範型編程相比較。
當然,如果你已經熟悉範型編程,大可以跳過這一節!這裏是目錄。
BGL的源代碼是Boost分發包的一部份,你可以在這裏下載。
如何構建BGL
根本不用!Boost 圖類庫是一個僅有頭文件(header-only)的類庫,並不需要構建後才能使用。唯一的例外是GraphViz輸入分析器 。
當編譯使用BGL的程序時,記住開啓優化。例如,在Microsoft Visual C++中選擇Release模式,或給GCC加上-O2或-O3選項。
STL中的範型
STL以三種方式體現出它是範型的。
Algorithm/Data-Structure Interoperability
算法/數據結構互操作性
首先,每個算法都是以一種數據結構中性的方式寫成的,允許一個單獨的模板函數在許多不同類型的容器施行操作。迭代器的概念是降低算法和數據結構耦合程度的關鍵因素。這項技術的影響在於將STL的代碼規模從O(M*N)降低到O(M+N),其中是M算法的數量而N是容器的數量。考慮有20種算法和5種數據結構的情形,這將是寫100個函數與僅寫25個函數的區別!而且這種區別將隨着算法和數據結構數目的增多而變得更大。
Extension through Function Objects
可擴展性(通過函數對象)
其次,STL的算法和數據結構是可擴展的。通過使用函數對象,用戶可以改造和定製STL。正是這種彈性使得STL成爲解決現實問題的優秀工具。每個編程問題都會帶來它自己的實體集合和需要建模的交互。函數對象提供了這樣一種機制來擴展STL使其能處理每個問題領域的細節。
Element Type Parameterization
元素類型的參數化
第三,STL容器的元素類型是參數化的。雖然這點非常重要,但它可能是最不有趣的一種方式。範性編程常常被簡單地總結爲參數化的列表,如std::list<T>。這僅僅撓到了問題的皮毛!
Boost Graph 庫中的範型
如同STL,BGL也以三種方式體現出它是範型的。
Algorithm/Data-Structure Interoperability
算法/數據結構互操作性
首先,BGL的圖算法是按照一個抽象掉了特定的圖結構的細節的接口寫成的。和STL一樣,BGL使用迭代器來定義數據結構遍歷的接口。有三種不同的圖遍歷模式:遍歷圖的所有頂點,經過所有的邊,以及沿着圖的鄰接結構(從一個頂點到它的鄰居)。對每一種遍歷模式,都有一種專門的迭代器。
該範型接口使得像breadth_first_search()這樣的模板函數可以工作於多種多樣的圖結構之上,無論是以指針鏈接的節點實現的圖,還是編碼在數組裏的圖。這種彈性對於圖論領域尤其重要。圖結構常常是爲特定的應用定製的。在以前,如果程序員想要重用一個算法實現他們必須將他們的圖數據轉換/複製到圖類庫的規定的圖結構。在使用像LEDA, GTL, Stanford GraphBase這樣的庫的時候,正是這樣;對於用Fortran寫成的圖算法,就更是如此。這嚴重地限制了它們的圖算法的重用。
相反,通過外部適配(external adaptation,參見小節如何將既有的圖轉換爲BGL),定製的(或者甚至是遺留的)圖結構可以原封不動地與BGL範型圖算法共同使用。外部適配將一個新的接口包裹在一個數據結構外面,無需複製,也無需將數據放在適配對象裏。BGL的接口經過仔細的設計,以使這個適配的過程儘可能簡單。爲了演示這一點,在BGL圖算法中,我們爲多種圖結構(LEDA圖、Stanford GraphBase圖,甚至 Fortran風格的數組)構建了接口連接代碼。
Extension through Visitors
可擴展性(通過Visitor)
其次,BGL的圖算法是可擴展的。BGL引入了visitor(訪問子)的概念,其實它只是一個有多個方法的函數對象。在圖算法中,常常需要在一些關鍵點(event points )插入用戶定義的操作。訪問子對象有一個不同的、只在關鍵點才調用的方法。具體的關鍵點以及相應的訪問子方法依具體的算法而定。它們通常包括像start_vertex(), discover_vertex(), examine_edge(), tree_edge(), and finish_vertex()這樣的方法。
Vertex and Edge Property Multi-Parameterization
頂點和邊屬性的多重參數化
BGL的第三種範型方式,類似於STL容器中的元素類型的參數化,可是情況比STL容器要複雜一些。我們既需要將值(稱爲“屬性”)關聯於圖的頂點,也需要關聯於邊。另外,常常需要將多重屬性關聯於每個頂點和每條邊;這正是所謂的多重參數化。STL的std::list<T> 類有一個參數T指定它的元素類型。相似地,BGL圖類有對應於頂點和邊的屬性的模板參數。一個屬性參數指定屬性的參數化的類型,同時給該屬性分派一個識別標籤。這個標籤用於區分開一個頂點或邊所具有的多個屬性。關聯於一個特定的頂點或邊的屬性值,可以經由一個屬性映射表(property map)獲得。對每一個屬性,都有一張單獨的屬性映射表。
傳統的圖庫和圖結構會在遇到圖屬性參數化時變得無能爲力。這是圖結構必須爲具體應用定製的一個主要原因。BGL中的圖類中屬性的參數化使得它們非常適合於重用。
Algorithms 算法
BGL算法包括一個算法模式(實現爲範型算法)的核心集合,以及大量的圖算法。核心的算法模式有:
- 廣度優先搜索(Breadth First Search )
- 深度優先搜索(Depth First Search )
- 成本一致搜索(Uniform Cost Search )
這些算法模式自身並不對圖計算任何有意義的量;他們僅僅爲構造圖算法建築基石。BGL中現有的圖算法包括:
- Dijkstra最短路徑(Dijkstra's Shortest Paths)
- Bellman-Ford最短路徑(Bellman-Ford Shortest Paths)
- Johnson所有節點對間最短路徑(Johnson's All-Pairs Shortest Paths)
- Kruskal最小生成樹(Kruskal's Minimum Spanning Tree)
- Prim最小生成樹(Prim's Minimum Spanning Tree)
- 連通區域(Connected Components)
- 強連通區域(Strongly Connected Components)
- 動態連通區域(使用不相交集合)(Dynamic Connected Components (using Disjoint Sets) )
- 拓撲排序(Topological Sort)
- 轉置(Transpose)
- 逆Cuthill Mckee排序(Reverse Cuthill Mckee Ordering)
- 最小最後頂點排序(Smallest Last Vertex Ordering)
- 順序頂點染色(Sequential Vertex Coloring)
Data Structures 數據結構
BGL目前提供兩個圖類和一個邊鏈表適配器。
adjacency_list類是通用目的的,是圖類中的瑞士軍刀。它是高度參數化的,因此它可以爲不同場合進行優化:圖是有向的還是無向的,是否允許平行邊,只可以高效訪問出邊還是也可高效訪問入邊,快速頂點插入與刪除的額外空間開銷等等。
adjacency_matrix將邊儲存在一個|V| x |V| 矩陣中(其中|V|是頂點數)。這個矩陣的元素代表圖中的邊。鄰接矩陣表示特別適合於非常密集的圖,即邊的數目接近|V|2 。