1. 程式人生 > >單源最短路徑的迪克斯特拉(Dijkstra)演算法的改進

單源最短路徑的迪克斯特拉(Dijkstra)演算法的改進

Dijkstra演算法

1.定義概覽

Dijkstra(迪傑斯特拉)演算法是典型的單源最短路徑演算法,用於計算一個節點(節點需為源點)到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴充套件,直到擴充套件到終點為止。Dijkstra演算法是很有代表性的最短路徑演算法,注意該演算法要求圖中不存在負權邊。

 例項:假設有A,B,C,D四個城市,(這裡討論的是有向網) 它們的距離為:  A->B(10),A->C(11),B->D(12),C->D(13);

所謂単源路徑就是解決從源點 A開始找出到其他城市的最短距離(除本身外的其他所有城市)。Dijkstra演算法可以求出A->B(10),A->C(11),A->D(22);

拓展2:多源最短路徑(常用Floyd演算法)是解決任意兩點間的最短路徑的一種演算法,(不侷限於從源點出發,到其他各個頂點 )可以正確處理有向圖或負權的最短路徑問題,同時也被用於計算有向圖的傳遞閉包。Floyd演算法的時間複雜度為O(N3),空間複雜度為O(N2)。

圖的建立:

void createGraph(tnode t){
    cout<<"輸入頂點和邊數:"<<endl;
    cin>>t->v>>t->e;
    cout<<"輸入頂點資訊:"<<endl;
    for(int i = 1;i<=t->v;i++){
         cin>>t->vex[i];
    }
    for(int i = 1;i<=t->v;i++){
        for(int j = 1;j<=t->v;j++){
           t->wei[i][j] = LIMITLESS;
        }
    }
    cout<<"輸入兩連線點下標和權值:"<<endl;
    int k1,k2,weight;
    for(int i = 1;i<=t->e;i++){
        cin>>k1>>k2>>weight;
        t->wei[k1][k2] = weight;
    }
}
void  printGraph(tnode t){
       for(int i = 1;i<=t->v;i++){
          for(int j = 1;j<=t->v;j++){
              if(t->wei[i][j]!=LIMITLESS){
                  cout<<t->wei[i][j]<<"  ";
              }
              else{
                  cout<<"oo"<<"  ";
              }
          }
          cout<<endl;
      }
}
dijkstra演算法:
void dijkstra(tnode t,int sour){
     bool s[MAX_NUM];              //標識
     int dist[MAX_NUM];           //源點到頂點距離
     int prev[MAX_NUM] = {0};    //頂點的前置頂點
     for(int i = 1;i<=t->v;i++){
        dist[i] = t->wei[sour][i]; //記錄從源點到各頂點的路徑長
        s[i] = false;              //初始化標識陣列
        if(dist[i]!=LIMITLESS){    //若源點到頂點的距離不為空,則將源點置為頂點的前置點
           prev[i] = sour;
        }
        else{
            prev[i] = 0;         //0表示前置節點不存在
        }
     }
     dist[sour] = 0,s[sour] = true;
     for(int i = 1;i<t->v;i++){
         int item = LIMITLESS;
         int flag = sour;
         for(int j = 1;j<=t->v;j++){      //找到距源點距離最小且未被標識過的頂點
             if(!s[j]&&dist[j]<item){
                 flag = j;
                 item = dist[j];
             }
         }
         s[flag] = true;
         for(int i = 1;i<=t->v;i++){         //從上面找到的頂點向其它頂點探索,優化源點到其他頂點的距離
             if(!s[i]&&t->wei[flag][i]<LIMITLESS){
                int newdist = dist[flag]+t->wei[flag][i];
                if(newdist<dist[i]){        //其它頂點距離更新
                    dist[i] = newdist;
                    prev[i] = flag;
                }
             }
         }
     }
     stack<int> ss[MAX_NUM];        //棧實現列印路徑構建
     for(int i = 1;i<=t->v;i++){
         cout<<"\n源點到頂點"<<i<<"的最短距離為:"<<dist[i];
         cout<<",最短路徑構建為:"<<endl;
         int p = prev[i];
         if(!p){
             cout<<"源點到自身路徑構建為空!"<<endl;
         }else{
             while(p){
                ss[i].push(p);
                p = prev[p];
             }
             while(!ss[i].empty()){
                int k = ss[i].top();
                cout<<k;
                ss[i].pop();
                if(!ss[i].empty()){
                    cout<<"->";
                }
             }
             if(i!=sour) cout<<"->"<<i;     //頂點自身值列印
         }
     }
完整程式碼:
/**
   @單源最短路徑(dijkstra演算法)
*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stack>
#define MAX_NUM 50
#define LIMITLESS 65535
using namespace std;
typedef struct Tnode{
    int v,e;
    int vex[MAX_NUM];
    int wei[MAX_NUM][MAX_NUM];
}Tnode,*tnode;
void createGraph(tnode t){
    cout<<"輸入頂點和邊數:"<<endl;
    cin>>t->v>>t->e;
    cout<<"輸入頂點資訊:"<<endl;
    for(int i = 1;i<=t->v;i++){
         cin>>t->vex[i];
    }
    for(int i = 1;i<=t->v;i++){
        for(int j = 1;j<=t->v;j++){
           t->wei[i][j] = LIMITLESS;
        }
    }
    cout<<"輸入兩連線點下標和權值:"<<endl;
    int k1,k2,weight;
    for(int i = 1;i<=t->e;i++){
        cin>>k1>>k2>>weight;
        t->wei[k1][k2] = weight;
    }
}
void  printGraph(tnode t){
       for(int i = 1;i<=t->v;i++){
          for(int j = 1;j<=t->v;j++){
              if(t->wei[i][j]!=LIMITLESS){
                  cout<<t->wei[i][j]<<"  ";
              }
              else{
                  cout<<"oo"<<"  ";
              }
          }
          cout<<endl;
      }
}
void dijkstra(tnode t,int sour){
     bool s[MAX_NUM];              //標識
     int dist[MAX_NUM];           //源點到頂點距離
     int prev[MAX_NUM] = {0};    //頂點的前置頂點
     for(int i = 1;i<=t->v;i++){
        dist[i] = t->wei[sour][i]; //記錄從源點到各頂點的路徑長
        s[i] = false;              //初始化標識陣列
        if(dist[i]!=LIMITLESS){    //若源點到頂點的距離不為空,則將源點置為頂點的前置點
           prev[i] = sour;
        }
        else{
            prev[i] = 0;         //0表示前置節點不存在
        }
     }
     dist[sour] = 0,s[sour] = true;
     for(int i = 1;i<t->v;i++){
         int item = LIMITLESS;
         int flag = sour;
         for(int j = 1;j<=t->v;j++){      //找到距源點距離最小且未被標識過的頂點
             if(!s[j]&&dist[j]<item){
                 flag = j;
                 item = dist[j];
             }
         }
         s[flag] = true;
         for(int i = 1;i<=t->v;i++){         //從上面找到的頂點向其它頂點探索,優化源點到其他頂點的距離
             if(!s[i]&&t->wei[flag][i]<LIMITLESS){
                int newdist = dist[flag]+t->wei[flag][i];
                if(newdist<dist[i]){        //其它頂點距離更新
                    dist[i] = newdist;
                    prev[i] = flag;
                }
             }
         }
     }
     stack<int> ss[MAX_NUM];        //棧實現列印路徑構建
     for(int i = 1;i<=t->v;i++){
         cout<<"\n源點到頂點"<<i<<"的最短距離為:"<<dist[i];
         cout<<",最短路徑構建為:"<<endl;
         int p = prev[i];
         if(!p){
             cout<<"源點到自身路徑構建為空!"<<endl;
         }else{
             while(p){
                ss[i].push(p);
                p = prev[p];
             }
             while(!ss[i].empty()){
                int k = ss[i].top();
                cout<<k;
                ss[i].pop();
                if(!ss[i].empty()){
                    cout<<"->";
                }
             }
             if(i!=sour) cout<<"->"<<i;     //頂點自身值列印
         }
     }
}
int main(){
     Tnode t;
     createGraph(&t);
     cout<<"構建的圖為:"<<endl;
     printGraph(&t);
     cout<<"dijkstra演算法構建的頂點最短路徑為:"<<endl;
     dijkstra(&t,1);
    return 0;
}
/*
1 2 10
1 4 30
1 5 100
2 3 50
3 5 10
4 3 20
4 5 60
*/