广度优先搜索(BreadthFirstSearch) 迪克斯特拉算法 (Dijkstra's algorithm)
BFS可回答兩類問題:
1.從節(jié)點(diǎn)A出發(fā),有前往節(jié)點(diǎn)B的路徑嗎?
2.從節(jié)點(diǎn)A出發(fā),前往節(jié)點(diǎn)B的哪條路徑經(jīng)過的節(jié)點(diǎn)最少?
BFS中會(huì)用到“隊(duì)列”的概念。隊(duì)列是一種先進(jìn)先出(FIFO, first in first out)的數(shù)據(jù)結(jié)構(gòu),與棧不同,棧是后進(jìn)先出(LIFO, last in first out)的數(shù)據(jù)結(jié)構(gòu)。
還會(huì)用到“字典”的概念。字典在現(xiàn)在很多語言中都存在且廣泛使用,字典中的元素是一組<鍵(key),值(value)>對(duì),key的值是不可以重復(fù)的。關(guān)于字典的詳細(xì)內(nèi)容,網(wǎng)上有很多資料可以查閱。
問題描述:想從你的朋友中找出一個(gè)芒果銷售商,如果你的朋友中沒有,那么就從朋友的朋友中查找。(這里假設(shè)名字最后一個(gè)字母為“m”的即為芒果銷售商)。這樣就是從“you”這個(gè)節(jié)點(diǎn)出發(fā),是否有到“Xm”這個(gè)節(jié)點(diǎn)的路徑的問題。
思路:先從你的朋友開始查找,如果朋友A是芒果銷售商,則程序結(jié)束,如果不是,則將A的朋友排到隊(duì)列中。然后檢查朋友B是否為芒果銷售商,循環(huán),直到找到芒果銷售商或者隊(duì)列中的朋友們都被檢查了一遍。因?yàn)闀?huì)有某個(gè)人C既是A的朋友又是B的朋友,而C只需要檢查一次,因此要分配一個(gè)列表用于記錄已經(jīng)檢查過哪些朋友了。
Python代碼:
>>> 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 Trueelse: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#代碼:
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;}} }測(cè)試:
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 用于計(jì)算出最短路徑,但是這個(gè)算法在使用上有很多限制條件。
問題描述:從A地到B地的各種可能的路徑中,哪條路徑所用的時(shí)間最短。(圖中的數(shù)字表示從某地到另外某地所用的時(shí)間)
?
?
?
圖1
思路:記錄從A點(diǎn)到其他各個(gè)節(jié)點(diǎn)的所需的時(shí)間,如表1所示(現(xiàn)在還不知道從A到B的時(shí)間,則先設(shè)置為無窮大)
| D | 3 |
| C | 7 |
| B | ∞ |
?
表1
?
?
從所需時(shí)間最短的D點(diǎn)再出發(fā),計(jì)算從A經(jīng)過D到其他個(gè)各節(jié)點(diǎn)的時(shí)間,如表2所示
?
| C | 5 |
| B | 10 |
表2
?
?
直接前往C點(diǎn)需要的時(shí)間為7,而經(jīng)過D點(diǎn)前往C點(diǎn)所需的時(shí)間為5,時(shí)間縮短了,則更新從A到各個(gè)點(diǎn)所需的時(shí)間的列表,如表3所示
?
| D | 3 |
| C | 5 |
| B | 10 |
?
表3
?
?
現(xiàn)在除了節(jié)點(diǎn)D之外,從A到C的時(shí)間是最短的了,則計(jì)算從A經(jīng)過C再到其他節(jié)點(diǎn)的時(shí)間,如表4所示。
?
| B | 7 |
表4
?
現(xiàn)在從A經(jīng)過D再經(jīng)過C然后到B的時(shí)間為7,小于表3記錄的到B的時(shí)間,則更新這個(gè)時(shí)間。
就這樣得到了花費(fèi)時(shí)間最短的路徑。總結(jié)一下就是,不斷的獲得從起點(diǎn)到某點(diǎn)的最短時(shí)間,然后更新這個(gè)時(shí)間列表。在?Dijkstra's algorithm中,這些數(shù)字被稱為“權(quán)重(weight)”,而帶權(quán)重的圖則被稱為加權(quán)圖(weighted graph),那么不帶權(quán)重的則被稱為非加權(quán)圖(unweighted graph)。對(duì)于計(jì)算非加權(quán)圖中的最短路徑,可使用BFS,計(jì)算加權(quán)圖中的最短路徑,可使用?Dijkstra's algorithm。然而,?Dijkstra's algorithm不適用于帶環(huán)的圖,即圖1中的箭頭如果是雙向的話那么就是不適用的。此外,它還不適用于帶有負(fù)權(quán)重的情況。
Dijkstra算法的實(shí)現(xiàn)需要使用三個(gè)散列表。第一個(gè)散列表記錄的是每個(gè)點(diǎn)的鄰居及權(quán)重。第二個(gè)散列表記錄的是從起點(diǎn)開始到每個(gè)節(jié)點(diǎn)的權(quán)重,第三個(gè)散列表記錄的是各個(gè)節(jié)點(diǎn)父節(jié)點(diǎn)。
Python代碼:
#第一個(gè)散列表,記錄每個(gè)點(diǎn)的鄰居及權(quán)重 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"]={}#第二個(gè)散列表,記錄從起點(diǎn)A到其他各個(gè)節(jié)點(diǎn)的權(quán)重 #由于節(jié)點(diǎn)B不是A的鄰居,則A到B的權(quán)重暫設(shè)置為無窮大 costs={} infinity = float("inf") costs["C"]=7 costs["D"]=3 costs["B"]=infinity#第三個(gè)散列表,用于存儲(chǔ)節(jié)點(diǎn)的父節(jié)點(diǎn) parents={} parents["C"]="A" parents["D"]="A" parents["B"]=None#用于記錄已經(jīng)處理過的節(jié)點(diǎn)的數(shù)組 processed=[]#先在未處理的節(jié)點(diǎn)數(shù)組中找到權(quán)重最小的節(jié)點(diǎn) def find_lowest_cost_node(costs):lowest_cost = float("inf")lowest_cost_node = Nonefor node in costs:cost = costs[node]if cost < lowest_cost and node not in processed:lowest_cost = costlowest_cost_node = nodereturn lowest_cost_nodenode = 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_costparents[n]=nodeprocessed.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")運(yùn)行結(jié)果:
Node:C Cost:5Node:D Cost:3Node:B Cost:7ChildNode:C ParentNode:DChildNode:D ParentNode:AChildNode: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;}}字典的初始化以及運(yùn)行結(jié)果:
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();轉(zhuǎn)載于:https://www.cnblogs.com/larissa-0464/p/10633934.html
總結(jié)
以上是生活随笔為你收集整理的广度优先搜索(BreadthFirstSearch) 迪克斯特拉算法 (Dijkstra's algorithm)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: u盘在电脑上显示未格式化是怎么回事 U盘
- 下一篇: 前端简易服务器