Dijkstra算法(单源最短路径)

Dijkstra算法

        Dijkstra算法解决的是带权重的有向图上单源最短路径问题,所谓单源最短路径,就是固定一个顶点为源点,求源点到其他每个顶点的最短路径,该算法要求图上所有边的权值为非负值。

        Dijkstra算法在运行过程中,将整个图划分为两个点集合S与T,其中源点s到点集合S中所有顶点的最短路径已经被找到,而s到T中所有顶点的最短路径还没有被找到。初始时,集合S中只有源点s;算法重复地从点集合T中选择当前长度最小的一条最短路径的顶点u,将u加入到集合S,然后修改从顶点0到T中各顶点的最短路径长度;重复这一步骤,直到所有顶点都加入到集合S中,算法结束。在下面给出的伪代码中,我们利用一个最小优先队列实现该算法,优先队列中保存的元素为(源点到顶点u的最短距离d[u],顶点u),优先队列中的元素按照关键字d[u]升序排列。

初始化,清除所有点的标号

令d[0] = 0,其他d[i] = INF

源点s入队列

队列非空{

    在所有未标号的顶点中选择d值最小的顶点u

    u出队

    给顶点u标号

    对于所有从u出发的边(u,v),更新d[v] = min{d[v],d[u] + w(u,v)}

}

Dijkstra算法的执行过程如下所示:


1.源点0入队


2.源点0出队,更新d[1] = 1、d[2] = 7,顶点1、2入队


3.顶点1出队,更新d[3] = 10、d[5] = 16,顶点3、5入队


4.顶点2出队,更新d[4] = 11,顶点4入队


5.顶点3出队,更新d[5] = 15


6.顶点4出队,更新d[5] = 14


7.顶点5出队,算法结束

        使用邻接矩阵实现的Dijkstra算法的时间复杂度为O(|V|^2),而使用邻接表的话,更新最短距离只需要访问每条边一次即可,因此这部分的时间复杂度为O(|E|)。但是每次要枚举所有顶点来查找下一个使用的顶点,因此最终复杂度还是O(|V|^2)。使用堆优化后,每次从堆中取出的最小值都是下一次要使用的顶点。这样堆中的元素共有O(|V|)个,更新和取出数值的操作有O(|E|)次,因此整个算法的复杂度是O(|E|log|V|)。

        下面给出使用C++实现的Dijkstra算法核心代码

typedef pair<int,int> P;//first是最短距离,second是顶点的编号
struct edge
{
    int to;
    int dis;//权值
    edge(int to,int dis)
    {
        this -> to = to;
        this -> dis = dis;
    }
};
vector<edge> G[maxn];
int d[maxn];//最短距离
int V,E;//V顶点数,E边数
//初始化
void init()
{
    for(int i = 0;i < V;i++)
        G[i].clear();
}
//建图
void add_edge(int from,int to,int dis)
{
    G[from].push_back(edge(to,dis));
}

void dijkstra(int s)
{
    //通过指定greater<P>参数,堆按照first从小到大的顺序取出值
    priority_queue<P,vector<P>,greater<P> > que;
    for(int i = 0;i < V;i++)
        d[i] = INF;
    d[s] = 0;
    que.push(P(0,s));
    while(que.size()){
        P p = que.top();
        que.pop();
        int v = p.second;
        if(d[v] < p.first)
            continue;
        for(int i = 0;i < (int)G[v].size();i++){
            edge e = G[v][i];
            if(d[e.to] > d[v] + e.dis){
                d[e.to] = d[v] + e.dis;
                que.push(P(d[e.to],e.to));
            }
        }
    }
}


PS:水平有限,如有错误,请路过的各位指正,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值