数据结构:单源最短路径--Dijkstra算法

   Dijkstra算法

单源最短路径

    给定一带权图,图中每条边的权值是非负的,代表着两顶点之间的距离。指定图中的一顶点为源点,找出源点到其它顶点的最短路径和其长度的问题,即是单源最短路径问题。

Dijkstra算法

    求解单源最短路径问题的常用方法是Dijkstra(迪杰斯特拉)算法。该算法使用的是贪心策略:每次都找出剩余顶点中与源点距离最近的一个顶点。

算法思想

    带权图G=<V,E>,令S为已确定了最短路径顶点的集合,则可用V-S表示剩余未确定最短路径顶点的集合。假设V0是源点,则初始 S={V0}。用数组Distance表示源点V0到其余顶点的路径长度,用数组pre[i]表示最短路径序列上顶点i的前一个顶点。初始时,pre[i]都是源点的下标。接下来需重复两个步骤:

 

  1. 从当前Distance[i]找出最小的一个,记录其下标v=i,源点V0到顶点Vv的最短路径即已确定,把Vv加入S。
  2. 更新源点到剩余顶点的最短路径长度。更新方法是:以上一步的顶点Vv为中间点,若Distance[v]+weight(v,i)<Distance[i],则修改值:pre[i]=v;Distance[i]=Distance[v]+weight(v,i);

 

重复以上两个步骤,直至所有顶点的最短路径都已找到。需要指出,Dijkstra算法求解的不仅是有向图,无向图也是可以的。下面给出一个完整的有向带权图的实例:

 

 

实例

有向带权图

                       

Dijkstra算法的求解过程

其中,INF是infinity无穷大的意思。

代码

类定义

#include<iostream>    
#include<iomanip>  
#include<stack>  
using namespace std;  
#define MAXWEIGHT 100  
#ifdef INFINITY  
#undef INFINITY  
#endif  
#define INFINITY 1000  
class Graph  
{  
private:  
    //顶点数    
    int numV;  
    //边数    
    int numE;  
    //邻接矩阵    
    int **matrix;  
public:  
    Graph(int numV);  
    //建图    
    void createGraph(int numE);  
    //析构方法    
    ~Graph();  
    //迪杰斯特拉算法  
    void Dijkstra(int);  
    //打印邻接矩阵    
    void printAdjacentMatrix();  
    //检查输入    
    bool check(int, int, int);  
};  

类实现

//构造函数,指定顶点数目  
Graph::Graph(int numV)  
{  
    //对输入的顶点数进行检测  
    while (numV <= 0)  
    {  
        cout << "顶点数有误!重新输入 ";  
        cin >> numV;  
    }  
    this->numV = numV;  
    //构建邻接矩阵,并初始化  
    matrix = new int*[numV];  
    int i, j;  
    for (i = 0; i < numV; i++)  
        matrix[i] = new int[numV];  
    for (i = 0; i < numV; i++)  
    for (j = 0; j < numV; j++)  
    {  
        if (i == j)  
            matrix[i][i] = 0;  
        else  
            matrix[i][j] = INFINITY;  
    }  
}  
void Graph::createGraph(int numE)  
{  
    /* 
    对输入的边数做检测 
    一个numV个顶点的有向图,最多有numV*(numV - 1)条边 
    */  
    while (numE < 0 || numE > numV*(numV - 1))  
    {  
        cout << "边数有问题!重新输入 ";  
        cin >> numE;  
    }  
    this->numE = numE;  
    int tail, head, weight, i;  
    i = 0;  
    cout << "输入每条边的起点(弧尾)、终点(弧头)和权值" << endl;  
    while (i < numE)  
    {  
        cin >> tail >> head >> weight;  
        while (!check(tail, head, weight))  
        {  
            cout << "输入的边不正确!请重新输入 " << endl;  
            cin >> tail >> head >> weight;  
        }  
        matrix[tail][head] = weight;  
        i++;  
    }  
}  
Graph::~Graph()  
{  
    int i;  
    for (i = 0; i < numV; i++)  
        delete[] matrix[i];  
    delete[]matrix;  
}  
/* 
迪杰斯特拉算法 
求指定顶点vertex到其它顶点的最短路径 
不仅要得出最短路径长度,也要得到其序列 
*/  
void Graph::Dijkstra(int vertex)  
{  
    int i;  
    //最短路径序列中每个顶点的直接前驱  
    int *pre = new int[numV];  
    for (i = 0; i < numV; i++)  
        pre[i] = vertex;  
    //顶点vertex到各个顶点的路径长度  
    int *Distance = new int[numV];  
    //初始化路径长度  
    for (i = 0; i < numV; i++)  
        Distance[i] = matrix[vertex][i];  
    //标记各个顶点最短路径找到与否  
    bool *find = new bool[numV];  
    memset(find, 0, numV);  
    find[vertex] = true;  
    int d, v, count;  
    count = 1, v = vertex;  
    while (count < numV)  
    {  
        d = INFINITY;  
        //确定一个最短距离  
        for (i = 0; i < numV; i++)  
        {  
            if (!find[i] && Distance[i] < d)  
            {  
                d = Distance[i];  
                v = i;  
            }  
        }  
        find[v] = true;  
        //更新剩余顶点的前驱和最短距离  
        for (i = 0; i < numV; i++)  
        {  
            if (!find[i])  
            {  
                d = Distance[v] + matrix[v][i];  
                if (d < Distance[i])  
                {  
                    pre[i] = v;  
                    Distance[i] = d;  
                }  
            }  
        }  
        count++;  
    }  
    //打印最短路径序列和其长度  
    stack<int> s;  
    for (i = 0; i < numV; i++)  
    {  
        if (Distance[i] == 0);  
        else if (Distance[i] == INFINITY)  
            cout << "顶点 " << vertex <<" 到顶点 " << i <<" 无路径!" << endl;  
        else  
        {  
            cout << "顶点 " << vertex << " 到顶点 " << i   
                 << " 最短路径长度是 " << Distance[i]   
                 << " ,其序列是...";  
            v = i;  
            s.push(v);  
            do  
            {  
                v = pre[v];  
                s.push(v);  
            } while (v!=vertex);  
            //打印最短路径序列  
            while (!s.empty())  
            {  
                cout << setw(3) << s.top();  
                s.pop();  
            }  
            cout << endl;  
        }  
    }  
    cout << endl;  
    delete[]find;  
    delete[]pre;  
    delete[]Distance;  
}  
//打印邻接矩阵    
void Graph::printAdjacentMatrix()  
{  
    int i, j;  
    cout.setf(ios::left);  
    cout << setw(7) << " ";  
    for (i = 0; i < numV; i++)  
        cout << setw(7) << i;  
    cout << endl;  
    for (i = 0; i < numV; i++)  
    {  
        cout << setw(7) << i;  
        for (j = 0; j < numV; j++)  
            cout << setw(7) << matrix[i][j];  
        cout << endl;  
    }  
}  
bool Graph::check(int tail, int head, int weight)  
{  
    if (tail < 0 || tail >= numV || head < 0 || head >= numV  
        || weight <= 0 || weight >= MAXWEIGHT)  
        return false;  
    return true;  
}  

主函数

int main()  
{  
    cout << "******Dijkstra***by David***" << endl;  
    int numV, numE;  
    cout << "建图..." << endl;  
    cout << "输入顶点数 ";  
    cin >> numV;  
    Graph graph(numV);  
    cout << "输入边数 ";  
    cin >> numE;  
    graph.createGraph(numE);  
    cout << endl << "Dijkstra..." << endl;  
    for (int i = 0; i < numV; i++)  
    graph.Dijkstra(i);  
    system("pause");  
    return 0;  
}  

运行

 

 

 

完整代码下载:Dijkstra算法

 

转载请注明出处,本文地址:http://blog.csdn.net/zhangxiangdavaid/article/details/38360337


若有所帮助,顶一个哦!

posted @ 2018-01-26 12:41  tsvico  阅读(325)  评论(0编辑  收藏  举报