【算】最短路徑問題

楔子

最短路徑是很經典的一個問題,最初看到該類問題時毫無思路,而一旦抓到解題思路的主脈絡後,則會驚歎於組織結構化數據的精巧!java

問題

clipboard.png

a、b、c、d、e、f、g是七個城鎮,它們之間的連線表示汽車行駛路線,而連線上的箭頭表示道路容許方向。(好比,a和c之間,箭頭由a指向c,表示能夠開車從a行駛到c;反之,從c直接行駛到a是不行的)問題,找出一條從A鎮到G鎮途徑鎮子最少的路線node

思路

解決問題的思路是這樣的:算法

步驟1

從節點a開始,查找可直接到達的節點,也就是節點e和c,姑且把它們稱之爲一級節點。緩存

clipboard.png

一級節點(e、c)中是否有終點g?很顯然沒有,那麼從e、c開始,繼續查找。數據結構

步驟2

clipboard.png

  • 從節點e開始好了,它可直達的節點是d、a、f(二級節點),其中是否有終點g?依然沒有。
  • 節點c可直達的節點仍是f(二級節點),也不是終點g。

接下來怎麼作?猜到了吧——查看三級節點!等等,我聞到了遞歸的味道。工具

步驟3

clipboard.png

避免忘記,我將步驟2時代的二級節點d、a、f標註顏色了。
從節點d開始,可直達節點g……hold on!其它的不用管了,咱們已經找到了終點g,路徑爲a->e->d->gthis

關鍵

思路不難理解,接下來的工做就是將上述思路翻譯成代碼思惟,關鍵點有三。google

  • point1 隊列

回顧下整個查找過程,從起點a的直達節點一級節點,到一級節點下的二級節點,再到二級節點下的三級節點……每步驟下來,有明確的前後次序。那什麼數據結構用來處理這種次序呢?FIFO(First In First Out)隊列!spa

從起點a開始,遍歷查找它的一級節(e、c)點中是否有終點g,有就開香檳慶祝,沒有則將這些節點放入到隊列中;而後從隊列中獲取這些一級節點(e、c),遍歷查找它們的可直達節點(二級節點),依然是「有就開香檳慶祝,沒有則將這些節點放入到隊列中」……翻譯

  • point2 遞歸

這個很少說了,前面的 步驟 2 和上面的 point 1 都流露出遞歸的痕跡,細細體會一下。

  • point3 重複節點

前面的分析中,有一個問題被輕易的略過了。

clipboard.png

起點a的直達節點中有節點e,節點e的直達節點中也有節點a,它倆你中有我我中有你當然親密無間,但聽任無論的話就陷入死循環了。

因此還要有一個去重機制,這裏我選擇了用一個Set集合記錄放入隊列節點的方式進行去重。

代碼

ok,最後將前面的各類分析造成代碼。

Node節點

其實就是bean,對節點數據進行封裝。
用到了lombok,挺好用的工具,感興趣的朋友自行研究下。

import lombok.Data;

/**
 * @description: 封裝節點數據
 * @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<String,List<Node>> pic = new HashMap<>();   //存儲圖
    Set<String> existsNodes = new HashSet<>();  //節點去重
    LinkedList<Node> pathList = new LinkedList<>(); //FIFO隊列

    /**
     * 圖的初始化
     */
    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.<Node>of());
    }

    /**
     * 構造塊中進行圖的初始化工做
     */
    public ShortestPath(){
        initPic();
    }

    /**
     * 路徑查找方法的重載
     * 爲調用方便,將參數source由<code>Node</code>類型重載爲<code>String</code>類型
     */
    public void findPath(String source,final String target){
        findPath(new Node(source),target);
    }

    /**
     * 核心方法,路徑查找
     */
    private void findPath(Node source,final String target){
        List<Node> relations = 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,以前老是對它只知其一;不知其二的。最近兩天有幸拜讀公司大神同事,用Guava Cache做本地緩存的代碼,敬畏不已!遂決定潛心研究之並寫文章記錄,敬請期待。

相關文章
相關標籤/搜索