最短路徑算法—狄傑斯特拉算法
一.介紹
這是一種按照路徑長度遞增的次序產生最短路徑的算法,採用的是貪心的思想,對帶權圖(有向和無向均可)尋找最短路徑;該算法對於不含負權的網來說,是目前已知的最快的單源最短路徑算法,時間複雜度爲o(n^2)
二.算法介紹與代碼實現
首先我們看以這張圖爲例:
該圖的領接矩陣表示爲:
1.首先我們需要三個數組(數組下標從1開始)
mark:用來標記單源頂點(我們這裏取爲頂點1)到該頂點的最短路徑是否已經求到了
dist:標誌單源頂點到該頂點的最短路徑長度
path:表示到該節點的前驅節點
2.三個數組初始化
mark: 1 0 0 0 0
dist: 0 3 30
path: 0 1 1 1 1
3.算法開始
狄傑斯特拉算法的核心思想是通過已有的最短路徑以他爲參照來優化到其他頂點的最短路徑。
簡單的概括過程就是每次從mark=0的頂點中去尋找dist最小的那個點那麼這個點的最短路徑就找到了,接下來從該頂點出發把剩下的mark=0的頂點的dist進行一遍優化(注意是優化,此時不一定是最短的路徑),當然在上述過程中要注意對mark與path的更新,下面我們用上面的例子演示一下。
mark: 1 0 0 0 0
dist: 0 3 30
path: 0 1 1 1 1
找從mark=0最小的dist,即3,於是更新得到,mark[2]=1,path[2]就是1不用更新,然後用得到的新的最短路徑去更新剩下的mark=0,那麼有dist[3]=3+25<,dist[4]=3+8<,dist[5]仍然爲30,因爲3+>30,同時更新path[3]=2,path[4]=2
此時:
mark: 1 1 0 0 0
dist: 0 3 28 11 30
path: 0 1 2 2 1
接下來按照上面的方式最後得到
4.代碼實現
import org.junit.Test;
import java.util.Scanner;
public class Test1 {
int INFINITY = 65535;
int [][]Vertex={
{},
{0,0,3,INFINITY,INFINITY,30},
{0,INFINITY,0,25,8,INFINITY},
{0,INFINITY,INFINITY,0,INFINITY,10},
{0,20,INFINITY,4,0,12},
{0,5,INFINITY,INFINITY,INFINITY,0}
};//領接矩陣
int []mark={0,1,0,0,0,0};
int []path={0,0,1,1,1,1};
int []dist={0,0,3,INFINITY,INFINITY,30};
@Test
public void Test() {
Dijstra(5);
for(int i=1;i<=5;i++){
System.out.print(mark[i]+" ");
}
System.out.println();
for(int i=1;i<=5;i++){
System.out.print(dist[i]+" ");
}
System.out.println();
for(int i=1;i<=5;i++){
System.out.print(path[i]+" ");
}
}
//傳入頂點數
void Dijstra(int n){
int marknum=n-1;//記錄0的個數
int index;
while (marknum>=1)
{
index = Find(n);
mark[index]=1;//表示找到最短路徑了
for(int i=1;i<=n;i++){
if(mark[i]==0&&Vertex[index][i]+dist[index]<dist[i])
{
dist[i]=Vertex[index][i]+dist[index];
path[i]=index;
}
}
marknum--;
}
}
//尋找mark爲0的dist最小頂點
int Find(int n){
int index = 1;
while(mark[index]!=0)
index++;
int min = dist[index];
for(int i=index+1;i<=n;i++){
if(mark[i]==0&&dist[i]<min) {
index=i;
min=dist[i];
}
}
return index;
}
}
輸出:
1 1 1 1 1
0 3 15 11 23
0 1 4 2 4
當然上面的圖的信息都是直接保存在數組裏面,我們也可以定義Graph類,在構造方法中完成初始化
//定義圖類
class Graph{
int INFINITY = 65535;
int [][]Vertex;//領接矩陣
int []mark;
int []path;
int []dist;
String[] name;//記錄每個節點的別名
Scanner scanner;
public Graph(){
//輸入節點的個數
scanner = new Scanner(System.in);
System.out.println("請輸入頂點的個數");
int n = scanner.nextInt();
System.out.println("請輸入邊的個數");
int numEdge = scanner.nextInt();
mark = new int[n+1];
mark[1]=1;
path = new int[n+1];
for(int i=1;i<=n;i++)
path[i]=1;
dist = new int[n+1];
Vertex = new int[n+1][n+1];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(i!=j)
Vertex[i][j]=INFINITY;
}
for(int i=2;i<=n;i++)
dist[i]=Vertex[1][i];
name = new String[n+1];
System.out.println("請依次輸入每個頂點的名字");
for(int i=1;i<=n;i++)
{
name[i]=scanner.next();
}
System.out.println("請依次輸入每條邊,輸入方式爲:頂點1編號 頂點2編號 權重");
int row,col,weight;
for(int i=1;i<=numEdge;i++){
row = scanner.nextInt();
col = scanner.nextInt();
weight = scanner.nextInt();
Vertex[row][col]=weight;
}
scanner.close();
}
//打印領接矩陣
public void printVertex(){
for (int[] vertex : Vertex) {
for (int i : vertex) {
System.out.print(i+" ");
}
System.out.println();
}
}
//傳入頂點數
void Dijstra(int n){
int marknum=n-1;//記錄0的個數
int index;
while (marknum>=1)
{
index = Find(n);
mark[index]=1;//表示找到最短路徑了
for(int i=1;i<=n;i++){
if(mark[i]==0&&Vertex[index][i]+dist[index]<dist[i])
{
dist[i]=Vertex[index][i]+dist[index];
path[i]=index;
}
}
marknum--;
}
}
//尋找mark爲0的dist最小頂點
int Find(int n){
int index = 1;
while(mark[index]!=0)
index++;
int min = dist[index];
for(int i=index+1;i<=n;i++){
if(mark[i]==0&&dist[i]<min) {
index=i;
min=dist[i];
}
}
return index;
}
}