BFS可回答兩類問題:node
1.從節點A出發,有前往節點B的路徑嗎?算法
2.從節點A出發,前往節點B的哪條路徑通過的節點最少?數組
BFS中會用到「隊列」的概念。隊列是一種先進先出(FIFO, first in first out)的數據結構,與棧不一樣,棧是後進先出(LIFO, last in first out)的數據結構。數據結構
還會用到「字典」的概念。字典在如今不少語言中都存在且普遍使用,字典中的元素是一組<鍵(key),值(value)>對,key的值是不能夠重複的。關於字典的詳細內容,網上有不少資料能夠查閱。app
問題描述:想從你的朋友中找出一個芒果銷售商,若是你的朋友中沒有,那麼就從朋友的朋友中查找。(這裏假設名字最後一個字母爲「m」的即爲芒果銷售商)。這樣就是從「you」這個節點出發,是否有到「Xm」這個節點的路徑的問題。測試
思路:先從你的朋友開始查找,若是朋友A是芒果銷售商,則程序結束,若是不是,則將A的朋友排到隊列中。而後檢查朋友B是否爲芒果銷售商,循環,直到找到芒果銷售商或者隊列中的朋友們都被檢查了一遍。由於會有某我的C既是A的朋友又是B的朋友,而C只須要檢查一次,所以要分配一個列表用於記錄已經檢查過哪些朋友了。spa
Python代碼:code
>>> from collections import deque >>> 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] searched = [] while search_queue: person = search_queue.popleft() if person not in searched: if person_is_seller(person): print (person + " is a mango seller!") return True else: search_queue += graph[person] searched.append(person) return False >>> def person_is_seller(name): return name[-1] == 'm' >>> search("you") thom is a mango seller! True
C#代碼:blog
namespace Algorithms { public static class BFS { public static bool BreadthFirstSearch(string name, Dictionary<string,List<string>>graph) { Queue<string> search_queue = new Queue<string>(); foreach (var item in graph[name]) search_queue.Enqueue(item); List<string> searched = new List<string>(); while (search_queue.Count != 0) { string person = search_queue.Dequeue(); if (!searched.Contains(person)) { if (JudgeSeller(person)) { Console.WriteLine(person + " is a mango seller!"); return true; } else { foreach (var item in graph[person]) search_queue.Enqueue(item); searched.Add(person); } } } return false; } private static bool JudgeSeller(string name) { if (name[name.Length - 1] == 'm') return true; return false; } } }
測試:隊列
namespace Algorithms { class Program { static void Main(string[] args) { Dictionary<string, List<string>> graph = new Dictionary<string, List<string>>(); graph["you"] = new List<string>() { "alice", "bob", "claire" }; graph["alice"] = new List<string>() { "peggy" }; graph["bob"] = new List<string>() { "anuj", "peggy" }; graph["claire"] = new List<string>() { "thom", "jonny" }; graph["anuj"] = new List<string>(); graph["peggy"] = new List<string>(); graph["thom"] = new List<string>(); graph["jonny"] = new List<string>(); if (!BFS.BreadthFirstSearch("you", graph)) { Console.WriteLine("no mango seller!"); } Console.Read(); } } }
Dijkstra's algorithm 用於計算出最短路徑,可是這個算法在使用上有不少限制條件。
問題描述:從A地到B地的各類可能的路徑中,哪條路徑所用的時間最短。(圖中的數字表示從某地到另外某地所用的時間)
圖1
思路:記錄從A點到其餘各個節點的所需的時間,如表1所示(如今還不知道從A到B的時間,則先設置爲無窮大)
D | 3 |
C | 7 |
B | ∞ |
表1
從所需時間最短的D點再出發,計算從A通過D到其餘個各節點的時間,如表2所示
C | 5 |
B | 10 |
表2
直接前往C點須要的時間爲7,而通過D點前往C點所需的時間爲5,時間縮短了,則更新從A到各個點所需的時間的列表,如表3所示
D | 3 |
C | 5 |
B | 10 |
表3
如今除了節點D以外,從A到C的時間是最短的了,則計算從A通過C再到其餘節點的時間,如表4所示。
B | 7 |
表4
如今從A通過D再通過C而後到B的時間爲7,小於表3記錄的到B的時間,則更新這個時間。
就這樣獲得了花費時間最短的路徑。總結一下就是,不斷的得到從起點到某點的最短期,而後更新這個時間列表。在 Dijkstra's algorithm中,這些數字被稱爲「權重(weight)」,而帶權重的圖則被稱爲加權圖(weighted graph),那麼不帶權重的則被稱爲非加權圖(unweighted graph)。對於計算非加權圖中的最短路徑,可以使用BFS,計算加權圖中的最短路徑,可以使用 Dijkstra's algorithm。然而, Dijkstra's algorithm不適用於帶環的圖,即圖1中的箭頭若是是雙向的話那麼就是不適用的。此外,它還不適用於帶有負權重的狀況。
Dijkstra算法的實現須要使用三個散列表。第一個散列表記錄的是每一個點的鄰居及權重。第二個散列表記錄的是從起點開始到每一個節點的權重,第三個散列表記錄的是各個節點父節點。
Python代碼:
#第一個散列表,記錄每一個點的鄰居及權重 graph={} graph["A"]={} graph["A"]["C"]=7 graph["A"]["D"]=3 graph["C"]={} graph["C"]["B"]=2 graph["D"]={} graph["D"]["C"]=2 graph["D"]["B"]=7 graph["B"]={} #第二個散列表,記錄從起點A到其餘各個節點的權重 #因爲節點B不是A的鄰居,則A到B的權重暫設置爲無窮大 costs={} infinity = float("inf") costs["C"]=7 costs["D"]=3 costs["B"]=infinity #第三個散列表,用於存儲節點的父節點 parents={} parents["C"]="A" parents["D"]="A" parents["B"]=None #用於記錄已經處理過的節點的數組 processed=[] #先在未處理的節點數組中找到權重最小的節點 def find_lowest_cost_node(costs): lowest_cost = float("inf") lowest_cost_node = None for node in costs: cost = costs[node] if cost < lowest_cost and node not in processed: lowest_cost = cost lowest_cost_node = node return lowest_cost_node node = find_lowest_cost_node(costs) while node is not None: cost = costs[node] neighbors=graph[node] for n in neighbors.keys(): new_cost=cost + neighbors[n] if costs[n] > new_cost: costs[n] = new_cost parents[n]=node processed.append(node) node=find_lowest_cost_node(costs) for node in costs: print("Node:" + node+ " Cost:" + str(costs[node]) + "\r\n") for node in parents: print("ChildNode:" + node + " ParentNode:" + parents[node] + "\r\n")
運行結果:
Node:C Cost:5 Node:D Cost:3 Node:B Cost:7 ChildNode:C ParentNode:D ChildNode:D ParentNode:A ChildNode:B ParentNode:C >>>
C#代碼:
public class DijkstraAlgorithm { public Dictionary<string, double> Costs { get; set; } public Dictionary<string, string> Parents { get; set; } public Dictionary<string, Dictionary<string,double>> Graph { get; set; } private List<string> processed = new List<string>(); public DijkstraAlgorithm() { Costs = new Dictionary<string, double>(); Parents = new Dictionary<string, string>(); Graph = new Dictionary<string, Dictionary<string, double>>(); } public void Dijkstra_Algorithm() { string node = FindLowestCostNode(); while(node != null) { double cost = Costs[node]; Dictionary<string, double> neighbors = Graph[node]; foreach(KeyValuePair<string,double> item in neighbors) { double new_cost = cost + item.Value; if (Costs[item.Key] > new_cost) { Costs[item.Key] = new_cost; Parents[item.Key] = node; } } processed.Add(node); node = FindLowestCostNode(); } } private string FindLowestCostNode() { string lowestcostnode = null; double lowestcost = double.PositiveInfinity; foreach(KeyValuePair<string,double> item in Costs) { if(item.Value < lowestcost && !processed.Contains(item.Key)) { lowestcost = item.Value; lowestcostnode = item.Key; } } return lowestcostnode; } }
字典的初始化以及運行結果:
DijkstraAlgorithm Dalgorithm = new DijkstraAlgorithm(); Dalgorithm.Graph["A"] = new Dictionary<string, double>(); Dalgorithm.Graph["A"]["C"] = 7; Dalgorithm.Graph["A"]["D"] = 3; Dalgorithm.Graph["C"] = new Dictionary<string, double>(); Dalgorithm.Graph["C"]["B"] = 2; Dalgorithm.Graph["D"] = new Dictionary<string, double>(); Dalgorithm.Graph["D"]["C"] = 2; Dalgorithm.Graph["D"]["B"] = 7; Dalgorithm.Graph["B"] = new Dictionary<string, double>(); Dalgorithm.Costs["C"] = 7; Dalgorithm.Costs["D"] = 3; Dalgorithm.Costs["B"] = double.PositiveInfinity; Dalgorithm.Parents["C"] = "A"; Dalgorithm.Parents["D"] = "A"; Dalgorithm.Parents["B"] = null; Dalgorithm.Dijkstra_Algorithm(); foreach(KeyValuePair<string,double> item in Dalgorithm.Costs) { Console.WriteLine("Key : " + item.Key + " Value : " + item.Value); } foreach(KeyValuePair<string,string> item in Dalgorithm.Parents) Console.WriteLine("Key : " + item.Key + " Value : " + item.Value); Console.Read();