dijkstra算法_最短路径问题——迪杰斯特拉算法(Dijkstra)
假期過長,導致停更了好長時間,復習一道算法題找找感覺。
前段時間看到一篇文章,里面提到了統(tǒng)治世界的十大算法,其中之一就是迪杰斯特拉算法(Dijkstra),該算法主要解決的”最短路徑“這一類問題。說法雖然夸張了點,但它在實際生活中確實應用廣泛,例如地圖軟件等,大部分游戲中自動尋路等功能,使用到的 A*搜索算法也是基于迪杰斯特拉算法優(yōu)化而來。那么迪杰斯特拉算法是如何實現(xiàn)的呢?
假如我們現(xiàn)在有如下一個有向圖,圖中有 6 個頂點,編號分別為 1~6,帶有箭頭的直線表示的是能從一個頂點到達另外一個頂點,直線上的數(shù)字表示的是兩個頂點之間的距離,現(xiàn)在求頂點 1 到頂點 6 的最短距離。
由于圖中的點比較少,我們直接手動計算就能算出來這個結(jié)果,但是如果頂點很多,有成千上萬個,手動計算就很難了,我們只能通過程序來計算,那么我們的程序該如何寫呢?
思路
從圖中我們可以看到,頂點 1 只能直接到達頂點 2、3、5,不能直接到達頂點 6,所以要想從 1 到達 6,就必須得從其他頂點中轉(zhuǎn)。
我們定義一個數(shù)組,用來表示每個頂點到頂點 1 的距離,數(shù)組的索引表示的是頂點編號,數(shù)組元素的值表示的是到頂點 1 的最小距離。
開始我們在頂點 1 上,頂點 1 能到達 2、3、5,數(shù)組的狀態(tài)如下。
| 最小距離 | 0 | 60 | 10 | null | 50 | null |
從頂點 2 處中轉(zhuǎn),頂點 2 能到達頂點 4,距離為 35,所以頂點 1 到頂點 4 的距離為 60+35=95,數(shù)組狀態(tài)如下:
| 最小距離 | 0 | 60 | 10 | 95 | 50 | null |
| 最小距離 | 0 | 60 | 10 | 40 | 35 | null |
| 最小距離 | 0 | 60 | 10 | 40 | 35 | 140 |
| 最小距離 | 0 | 60 | 10 | 40 | 35 | 55 |
以上流程,就是迪杰斯特拉算法在計算最短路徑問題時的核心流程。
代碼實現(xiàn)
首先我們需要將這個有向圖用代碼表示出來,通常表示圖的方法有兩種:第一種是鄰接矩陣(也就是二維數(shù)組),第二種是鄰接表(也就是數(shù)組+鏈表),這里我們選用鄰接表法來表示一個有向圖。
另外我們還需要定義頂點之間的邊,一條邊有起點和終點,還有邊的權(quán)重信息,也就是長度,用類 Edge 表示。代碼如下:
private?class?Edge?{????//?起始定點
????public?int?s;
????//?終止定點
????public?int?t;
????//?邊的權(quán)重
????public?int?weight;
????Edge(int?s,?int?t,?int?weight)?{
????????this.s?=?s;
????????this.t?=?t;
????????this.weight?=?weight;
????}
}
有向圖我們用類 Graph 表示,類中有兩個屬性:頂點個數(shù) v 和描述頂點之間邊的信息的數(shù)組 adj,我們還提供了一個方法:addEdge,用來在兩個頂點之間添加一條邊。代碼如下:
public?class?Graph?{????//?頂點個數(shù)(頂點編號從0開始,在本文例子中,編號為0的頂點不存在)
????private?int?v;
????//?記錄每個頂點的邊
????private?LinkedList[]?adj;public?Graph(int?v)?{this.v?=?v;//?初始化this.adj?=?new?LinkedList[v];for?(int?i?=?0;?i?????????????adj[i]?=?new?LinkedList();
????????}
????}//?添加一條邊,從s到達tpublic?void?addEdge(int?s,?int?t,?int?weight)?{
????????Edge?edge?=?new?Edge(s,?t,?weight);
????????adj[s].add(edge);
????}
}
定義好了圖的描述信息后,接下來通過代碼來實現(xiàn)迪杰斯特拉算法,其代碼和注釋如下。
有兩處邏輯稍微解釋一下。第一處:flag 數(shù)組記錄的是已經(jīng)遍歷過的頂點,用來防止死循環(huán),例如頂點 1 能到達 2,我們接著會判斷 2 能到達哪些點,頂點 1 又能到達 5,5 也能到達 2,如果沒有 flag 數(shù)組來記錄頂點 2 我們已經(jīng)遍歷過了,那么我們就會繼續(xù)遍歷 2,這樣會導致死循環(huán)。第二處:predecessor 數(shù)組記錄的是路徑信息,數(shù)組的索引表示的頂點編號,元素的值表示的是哪一個頂點到達當前頂點的,例如:predecessor[3]=1 表示的是通過頂點 1 到達的頂點 3。
//?采用迪杰斯特拉算法找出從s到t的最短路徑public?void?dijkstra(int?s,?int?t)?{
????int[]?dist?=?new?int[v];????//?記錄s到每個頂點的最小距離,數(shù)組下標表示頂點編號,值表示最小距離
????boolean[]?flag?=?new?boolean[v];????//?記錄遍歷過的頂點,數(shù)組下標表示頂點編號,值表示是否遍歷過該頂點
????for?(int?i?=?0;?i?????????dist[i]?=?Integer.MAX_VALUE;????//?初始狀態(tài)下,將頂點s到其他頂點的距離都設(shè)置為無窮大
????}
????int[]?predecessor?=?new?int[v];?????//?記錄路徑,索引表示頂點編號,值表示到達當前頂點的頂點是哪一個
????Queue?queue?=?new?LinkedList<>();
????queue.add(s);
????dist[s]?=?0;????//?s->s的路徑為0while?(!queue.isEmpty())?{
????????Integer?vertex?=?queue.poll();if?(flag[vertex])?continue;?//?已經(jīng)遍歷過該頂點,就不再遍歷
????????flag[vertex]?=?true;for?(int?i?=?0;?i?????????????Edge?edge?=?adj[vertex].get(i);if?(dist[vertex]?//?如果出現(xiàn)了比當前路徑小的方式,就更新為更小路徑
????????????????dist[edge.t]?=?dist[vertex]?+?edge.weight;
????????????????predecessor[edge.t]?=?vertex;
????????????}
????????????queue.add(edge.t);
????????}
????}//?打印路徑
????System.out.println("最短距離:"?+?dist[t]);
????System.out.print(s);
????print(s,?t,?predecessor);
}
print 函數(shù)的作用是打印從頂點 s 到達頂點 t 的最短路徑中,需要經(jīng)過哪些點,具體代碼如下,就是一個遞歸調(diào)用,比較簡單:
//?打印路徑private?void?print(int?s,?int?t,?int[]?predecessor)?{
????if?(t?==?s)?{
????????return;
????}
????print(s,?predecessor[t],?predecessor);
????System.out.print("?->?"?+?t);
}
測試
根據(jù)文中的示例,構(gòu)建一個圖,進行結(jié)果測試,代碼如下:
public?static?void?main(String[]?args)?{????//?構(gòu)建圖
????Graph?graph?=?new?Graph(7);
????graph.addEdge(1,?2,?60);
????graph.addEdge(1,?3,?10);
????graph.addEdge(1,?5,?50);
????graph.addEdge(2,?4,?35);
????graph.addEdge(3,?4,?30);
????graph.addEdge(3,?5,?25);
????graph.addEdge(4,?6,?15);
????graph.addEdge(5,?2,?30);
????graph.addEdge(5,?6,?105);
????//?計算最短距離
????graph.dijkstra(1,?6);
}
測試結(jié)果:
總結(jié)
迪杰斯特拉算法的思想與廣度優(yōu)先搜索(BFS)的思路比較像,每次找到自己能到達的頂點,然后依次往外擴散,直到遍歷完所有頂點。
總結(jié)
以上是生活随笔為你收集整理的dijkstra算法_最短路径问题——迪杰斯特拉算法(Dijkstra)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么查看电脑有没有python_pyth
- 下一篇: dijkstra算法代码_深度好文:改变