1. 程式人生 > >圖解演算法學習筆記(六):廣度優先搜尋

圖解演算法學習筆記(六):廣度優先搜尋

本章內容;

  •        學習使用新的資料結構圖來建立網路模型;
  •        學習廣度優先搜尋;
  •        學習有向圖和無向圖;
  •        學習拓撲排序,這種排序演算法指出了節點之間的依賴關係。

1)圖簡介

假設你住在舊金山,要從雙子峰前往金門大橋。你想乘公交車前往,並希望換乘最少。可乘坐的公交車如下:

從圖中我們可以發現,前往進門大橋的最短路徑需要三步,這種問題被稱為最短路徑問題(shorterst-path problem)。

要確定如何從雙子峰前往金門大橋,需要兩個步驟:

  • 使用圖來建立問題模型。

  • 使用廣度優先搜尋解決問題。

2)圖是什麼

圖模擬一組連線,圖由節點(node)和邊(edge)組成。

3)廣度優先搜尋

廣度優先搜尋是一種用於圖的查詢演算法。可回答兩類問題:

從A節點有前往幾點B的路徑嗎?哪條路徑最短?

下面來看一個例子:假設你經營這一個芒果農場,需要尋找芒果經銷商,以便將芒果賣給他。為此,你可在朋友中查詢。

這種查詢很簡單,首先建立一個朋友名單。然後依次檢查名單中的每個人,看看他是否是芒果銷售商。

假設你沒有朋友是芒果銷售商,那麼你必須在朋友的朋友中查詢。

檢查名單中的每個人時,你都將其朋友加入名單。

1.查詢最短路徑

人物關係如圖所示:

在你看來,一度關係勝過二度關係,二度關係勝過三度關係,等等。因此,你應現在一度關係中搜索,確定其中沒有芒果銷售商後,才在二度關係中搜索。廣度優先搜尋就是這樣做的!

2.佇列

佇列的工作原理與現實生活中的佇列完全相同。假設你與朋友一起在公交車站排隊,如果你排在他前面,你講先上車。佇列只有兩種操作:入隊和出隊。

佇列是一種先進先出(First In First Out,FIFO)的資料結構,而棧是一種後進先出(Last In First Out, LIFO)的資料結構。

4)實現圖

使用散列表,表示節點與節點之間的關係!

有向圖與無向圖關係如圖:

5)實現演算法

概述一下演算法原理:

尋找芒果銷售商的Python原始碼為:

#從標準庫匯入佇列元素
from collections import deque

def person_is_seller(name):
      return name[-1] == 'm'

graph = {}
graph["you"] = ["alice", "bob", "claire"]
graph["bob"] = ["anuj", "peggy"]
graph["alice"] = ["peggy"]
graph["claire"] = ["thom", "jonny"]
graph["anuj"] = []
graph["peggy"] = []
graph["thom"] = []
graph["jonny"] = []

def search(name):
	#建立一個新佇列
    search_queue = deque()
    search_queue += graph[name]
    # This array is how you keep track of which people you've searched before.
    searched = []
    while search_queue:
		#隊首元素出隊
        person = search_queue.popleft()
        # Only search this person if you haven't already searched them.
        if not person in searched:
            if person_is_seller(person):
                print person + " is a mango seller!"
                return True
            else:
                search_queue += graph[person]
                # Marks this person as searched
                searched.append(person)
    return False

search("you")

6)小結

  • 廣度優先搜尋指出是否有從A到B的路徑。
  •  如果有,廣度優先搜尋將找出最短路徑。
  • 面臨類似於尋找最短路徑的問題時,可嘗試使用圖來建立模型,再使用廣度優先搜尋來解決問題。
  • 有向圖中的邊為箭頭,箭頭的方向指定了關係的方向。
  •  無向圖中的邊不帶箭頭,其中的關係是雙向的。
  •  佇列是先進先出(FIFO)的。
  •  棧是後進先出(LIFO)的。
  • 你需要按加入順序檢查搜尋列表中的人,否則找到的就不是最短路徑,因此搜尋列表必須是佇列。
  • 對於檢查過的人,務必不要再去檢查,否則可能導致無限迴圈。