摘要:楔子最短路徑是很經(jīng)典的一個(gè)問題,最初看到該類問題時(shí)毫無思路,而一旦抓到解題思路的主脈絡(luò)后,則會(huì)驚嘆于組織結(jié)構(gòu)化數(shù)據(jù)的精巧問題是七個(gè)城鎮(zhèn),它們之間的連線表示汽車行駛路線,而連線上的箭頭表示道路允許方向。
楔子
最短路徑是很經(jīng)典的一個(gè)問題,最初看到該類問題時(shí)毫無思路,而一旦抓到解題思路的主脈絡(luò)后,則會(huì)驚嘆于組織結(jié)構(gòu)化數(shù)據(jù)的精巧!
問題a、b、c、d、e、f、g是七個(gè)城鎮(zhèn),它們之間的連線表示汽車行駛路線,而連線上的箭頭表示道路允許方向。(比如,a和c之間,箭頭由a指向c,表示可以開車從a行駛到c;反之,從c直接行駛到a是不行的)問題,找出一條從A鎮(zhèn)到G鎮(zhèn)途徑鎮(zhèn)子最少的路線。
思路解決問題的思路是這樣的:
步驟1從節(jié)點(diǎn)a開始,查找可直接到達(dá)的節(jié)點(diǎn),也就是節(jié)點(diǎn)e和c,姑且把它們稱之為一級(jí)節(jié)點(diǎn)。
一級(jí)節(jié)點(diǎn)(e、c)中是否有終點(diǎn)g?很顯然沒有,那么從e、c開始,繼續(xù)查找。
步驟2從節(jié)點(diǎn)e開始好了,它可直達(dá)的節(jié)點(diǎn)是d、a、f(二級(jí)節(jié)點(diǎn)),其中是否有終點(diǎn)g?依然沒有。
節(jié)點(diǎn)c可直達(dá)的節(jié)點(diǎn)還是f(二級(jí)節(jié)點(diǎn)),也不是終點(diǎn)g。
接下來怎么做?猜到了吧——查看三級(jí)節(jié)點(diǎn)!等等,我聞到了遞歸的味道。
步驟3避免忘記,我將步驟2時(shí)代的二級(jí)節(jié)點(diǎn)d、a、f標(biāo)注顏色了。
從節(jié)點(diǎn)d開始,可直達(dá)節(jié)點(diǎn)g……h(huán)old on!其它的不用管了,我們已經(jīng)找到了終點(diǎn)g,路徑為a->e->d->g。
思路不難理解,接下來的工作就是將上述思路翻譯成代碼思維,關(guān)鍵點(diǎn)有三。
point1 隊(duì)列
回顧下整個(gè)查找過程,從起點(diǎn)a的直達(dá)節(jié)點(diǎn)一級(jí)節(jié)點(diǎn),到一級(jí)節(jié)點(diǎn)下的二級(jí)節(jié)點(diǎn),再到二級(jí)節(jié)點(diǎn)下的三級(jí)節(jié)點(diǎn)……每步驟下來,有明確的先后次序。那什么數(shù)據(jù)結(jié)構(gòu)用來處理這種次序呢?FIFO(First In First Out)隊(duì)列!
從起點(diǎn)a開始,遍歷查找它的一級(jí)節(jié)(e、c)點(diǎn)中是否有終點(diǎn)g,有就開香檳慶祝,沒有則將這些節(jié)點(diǎn)放入到隊(duì)列中;然后從隊(duì)列中獲取這些一級(jí)節(jié)點(diǎn)(e、c),遍歷查找它們的可直達(dá)節(jié)點(diǎn)(二級(jí)節(jié)點(diǎn)),依然是“有就開香檳慶祝,沒有則將這些節(jié)點(diǎn)放入到隊(duì)列中”……
point2 遞歸
這個(gè)不多說了,前面的 步驟 2 和上面的 point 1 都流露出遞歸的痕跡,細(xì)細(xì)體會(huì)一下。
point3 重復(fù)節(jié)點(diǎn)
前面的分析中,有一個(gè)問題被輕易的略過了。
起點(diǎn)a的直達(dá)節(jié)點(diǎn)中有節(jié)點(diǎn)e,節(jié)點(diǎn)e的直達(dá)節(jié)點(diǎn)中也有節(jié)點(diǎn)a,它倆你中有我我中有你固然親密無間,但放任不管的話就陷入死循環(huán)了。
所以還要有一個(gè)去重機(jī)制,這里我選擇了用一個(gè)Set集合記錄放入隊(duì)列節(jié)點(diǎn)的方式進(jìn)行去重。
代碼ok,最后將前面的各種分析形成代碼。
Node節(jié)點(diǎn)其實(shí)就是bean,對(duì)節(jié)點(diǎn)數(shù)據(jù)進(jìn)行封裝。
用到了lombok,挺好用的工具,感興趣的朋友自行研究下。
import lombok.Data; /** * @description: 封裝節(jié)點(diǎn)數(shù)據(jù) * @author: liuzijian * @date: 2018-04-11 23:06 */ @Data public class Node { private String node; private String path; //保存路徑 public Node(String node) { this.node = node; path = node; } private final String nextSymbol = "->"; //間隔符 public String pathAppend(String lastPath){ return lastPath + nextSymbol + node; } }ShortestPath算法
用到了guava中的ImmutableList,也是極好用的東西,推薦!
import com.evolution.algorithm.bean.Node; import com.google.common.collect.ImmutableList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; /** * @description: 最短路徑問題 * @author: liuzijian * @date: 2018-04-11 23:04 */ public class ShortestPath { Map后序> pic = new HashMap<>(); //存儲(chǔ)圖 Set existsNodes = new HashSet<>(); //節(jié)點(diǎn)去重 LinkedList pathList = new LinkedList<>(); //FIFO隊(duì)列 /** * 圖的初始化 */ private void initPic(){ pic.put("a",ImmutableList.of(new Node("c"),new Node("e"))); pic.put("b",ImmutableList.of(new Node("a"),new Node("g"))); pic.put("c",ImmutableList.of(new Node("f"))); pic.put("d",ImmutableList.of(new Node("a"),new Node("g"))); pic.put("e",ImmutableList.of(new Node("d"),new Node("a"),new Node("f"))); pic.put("f",ImmutableList.of(new Node("b"),new Node("d"))); pic.put("g",ImmutableList. of()); } /** * 構(gòu)造塊中進(jìn)行圖的初始化工作 */ public ShortestPath(){ initPic(); } /** * 路徑查找方法的重載 * 為調(diào)用方便,將參數(shù)source由 Node
類型重載為String
類型 */ public void findPath(String source,final String target){ findPath(new Node(source),target); } /** * 核心方法,路徑查找 */ private void findPath(Node source,final String target){ Listrelations = pic.get(source.getNode()); for(Node node:relations){ if(node.getNode().equals(target)){ System.out.println("Get it!Path is ""+node.pathAppend(source.getPath())+"""); return; }else if(existsNodes.contains(node.getNode())){ //do nothing }else{ existsNodes.add(node.getNode()); pathList.add(node); node.setPath(node.pathAppend(source.getPath())); } } if(pathList.isEmpty()){ System.out.println("Sorry!Can not reach!"); }else{ Node node = pathList.removeFirst(); findPath(node,target); } } public static void main(String[] args) { ShortestPath sp = new ShortestPath(); sp.findPath("d","f"); } }
近期比較癡迷Guava,之前總是對(duì)它一知半解的。最近兩天有幸拜讀公司大神同事,用Guava Cache作本地緩存的代碼,敬畏不已!遂決定潛心研究之并寫文章記錄,敬請(qǐng)期待。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69038.html
摘要:致敬首先向偉大的牛人致敬使用狄克斯特拉算法如果所示找出從起點(diǎn)到終點(diǎn)耗時(shí)最短的路徑。狄克斯特拉算法思路步驟或思路如下找出最便宜的節(jié)點(diǎn),即可在最短時(shí)間內(nèi)前往的節(jié)點(diǎn)。 狄克斯特拉算法是一種實(shí)現(xiàn)了在有障礙物的兩個(gè)地點(diǎn)之間找出一條最短路徑的高效算法,解決了機(jī)器人學(xué)中的一個(gè)十分關(guān)鍵的問題,即運(yùn)動(dòng)路徑規(guī)劃問題,至今仍被廣泛應(yīng)用。是貪心方法(greedy method)的一個(gè)成功范例。 致敬 首先向偉...
摘要:學(xué)習(xí)資料迪杰斯特拉計(jì)算的是單源最短路徑,而弗洛伊德計(jì)算的是多源最短路徑代碼不能設(shè)置為,否則兩個(gè)相加會(huì)溢出導(dǎo)致出現(xiàn)負(fù)權(quán)創(chuàng)建頂點(diǎn)和邊 學(xué)習(xí)資料 迪杰斯特拉計(jì)算的是單源最...
摘要:由于是從頂點(diǎn)到的最短路徑,則有。算法流程根據(jù)最短路徑的最優(yōu)子結(jié)構(gòu)性質(zhì),提出了以最短路徑長度遞增,逐次生成最短路徑的算法。相關(guān)文章王者編程大賽之一王者編程大賽之二蓄水池王者編程大賽之三背包王者編程大賽之四約瑟夫環(huán) 首發(fā)于 樊浩柏科學(xué)院 自如年底就會(huì)擁有 50W 間房子,大家知道每間房房子都是需要配置完才能出租給自如客的,整個(gè)房租的配置過程是很復(fù)雜的,每天都需要大量的物流師傅將家電、家具...
摘要:推薦資料推薦學(xué)習(xí)文章代碼不能設(shè)置為否則兩個(gè)相加會(huì)溢出導(dǎo)致出現(xiàn)負(fù)權(quán)創(chuàng)建頂點(diǎn)和邊創(chuàng)建圖頂點(diǎn)數(shù)得到邊的數(shù)目調(diào)用算法計(jì)算最短路徑 推薦資料 推薦學(xué)習(xí)文章 代碼 public...
摘要:算法系列單源最短路徑算法迪杰斯特拉算法是由荷蘭計(jì)算機(jī)科學(xué)家狄克斯特拉于年提出的,因此又叫狄克斯特拉算法。是從一個(gè)頂點(diǎn)到其余各頂點(diǎn)的最短路徑算法,解決的是有向圖中最短路徑問題。 Javascript算法系列 - 單源最短路徑 - Dijkstra算法 迪杰斯特拉算法是由荷蘭計(jì)算機(jī)科學(xué)家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是從一個(gè)頂點(diǎn)到其余各頂點(diǎn)的最短路徑算法,解決的是有...
閱讀 3910·2021-11-22 13:54
閱讀 2684·2021-09-30 09:48
閱讀 2365·2021-09-28 09:36
閱讀 3121·2021-09-22 15:26
閱讀 1348·2019-08-30 15:55
閱讀 2516·2019-08-30 15:54
閱讀 1428·2019-08-30 14:17
閱讀 2346·2019-08-28 18:25