Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

精通實用圖論與 Ruby 應用

這是「Practical Computer Science」系列的下一篇,你將學習如何應用經典電腦科學概念用 Ruby 解決真實問題。

今天我們要談 Graph Theory(圖論)。

你可能聽過 binary trees,長這樣:

精通實用圖論與 Ruby 應用

重點是 binary tree 只是 graph 的特化版本,這應該讓你對 graph 的普及程度有概念。

讓我們從圖論基礎概覽開始,然後看實際用途和如何在 Ruby 實作!

圖論基礎

一個圖由兩個元素組成:

  • Nodes(節點,或稱 vertices)
  • Edges(邊)

一個節點代表圖中的一個元素,像城市或街道,在地圖圖中。而邊代表節點間的連接。

如果你看電腦科學或數學書,會看到圖用這公式定義:G(V, E)。

G 是 Graph,V 是 vertices 集合,E 是 edges 集合。

圖可以是 directed(有向)或 undirected(無向)。意思是你只能單向(有向圖)或雙向(無向圖)。

最熱門的圖類型是 Directed Acyclic Graph (DAG)。Acyclic 意思是沒有迴路,無法回溯。

圖的用途

看完基礎概覽,來看圖的常見用途。

用圖你可以做:

  • 找兩地間最短(或最長)路徑
  • 檢查兩件事是否相關
  • 建立推薦引擎
  • 分析依賴關係

另一個例子是找到目的地的最佳路徑(想像 GPS 裝置)。

如何實作與使用圖

你可以自己寫圖實作,但這篇我們用 RGL gem,它已經實作好了。

用 RGL 建立基本圖:

 require 'rgl/adjacency' graph = RGL::DirectedAdjacencyGraph.new graph.add_edge 1,2 graph.add_edge 3,4 graph.add_edge 1,4 graph.add_edge 4,3 

這段代碼產生以下圖:

精通實用圖論與 Ruby 應用

你可以這樣取得圖的圖形表示:

 require 'rgl/dot' graph.print_dotted_on 

然後把那個方法的輸出複製到能處理 dot 語言的網站。像這個。

或者,你可以在機器上安裝 Graphviz 在本地產生圖片。

現在我們有圖了,可能想遍歷它來找資訊。

搜尋圖的兩個基本演算法:

  • Breadth-First Search (BFS)
  • Depth-First Search (DFS)

BFS 先取得最近的節點,DFS 則對每個節點盡可能深入。這些演算法可用 stack 資料結構實作。

RGL gem 已經幫你實作了那些演算法:

 require 'rgl/traversal' graph.bfs_iterator.to_a # [1, 2, 4, 3] graph.dfs_iterator.to_a # [1, 4, 3, 2] 

再看一次圖,用眼睛(或手指)跟著這些演算法的路徑。這會幫助你理解發生了什麼。

加權圖 (Weighted Graphs)

我們可以用權重給圖加更多資訊,使它更有用。

權重給邊,也就是 兩個節點間的路徑(也稱「vertices」)。這些權重代表從一點到另一點的成本。

例如,如果我們有國家地圖形式的圖,想用最短時間到達目的地,權重代表兩城市間的距離。

精通實用圖論與 Ruby 應用

或者如果我們有電腦網路,權重可能代表到達某網路需要多少 hops。

「在電腦網路中,hop 是來源和目的地之間路徑的一部分。資料封包在來源和目的地之間傳遞時會經過橋接器、路由器和閘道。每次封包傳遞給下一個網路裝置,就發生一個 hop。」 — Wikipedia

這裡有加權圖的程式碼範例:

 graph = RGL::DirectedAdjacencyGraph.new graph.add_vertices "Los Angeles", "New York", "Chicago", "Houston", "Seattle" edge_weights = { ["New York", "Los Angeles"] => 2445, ["Los Angeles", "Chicago"] => 2015, ["Los Angeles", "Houston"] => 1547, ["Chicago", "Houston"] => 939, ["Seattle", "Los Angeles"] => 1548 } edge_weights.each { |(city1, city2), w| graph.add_edge(city1, city2) } 

我們現在可以搜尋從一點到另一點的最短路徑。這正是下一節的主題!

尋找最短路徑

在圖中尋找最短路徑的熱門演算法是「Dijkstra's Shortest Path」演算法。

給定加權圖,我們可以用 Dijkstra 演算法解決這問題:

「從點 A 到點 B 最快的路是什麼?」

這裡有用 RGL gem 的程式碼範例:

 p graph.dijkstra_shortest_path(edge_weights, "New York", "Houston") # ["New York", "Los Angeles", "Houston"] 

這告訴我們從紐約到休士頓的最短路徑,用圖中可用的資訊。

總結

你學到了什麼是圖資料結構 以及如何用 RGL gem 使用它。

也學到了處理圖的常見演算法,像 DFS, BFS 和 Dijkstra's。

如果覺得有用別忘了分享這篇文章 讓更多人享受 🙂