Dijkstra's Algorithm分析以及其优化

本文详细介绍了Dijkstra算法的基本原理及其在解决单源最短路径问题中的应用,并提出了一种基于优先队列的优化方法,有效提高了算法的时间效率。
Dijkstra's  Algorithm


传统的Dijkstra:
适用于单源无负权边最短路问题。
算法步骤:
a.初始时,S只包含源点,即S{v}v的距离为0
U包含除v外的其他顶点,即:U={其余顶点},若vU中顶点u有边,则<u,v>正常有权值,
u不是v的出边邻接点,则<u,v>权值为∞。
b.U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是vk的最短路径长度)。
c.k为新考虑的中间点,修改U中各顶点的距离;
若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,
则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。
d.重复步骤bc直到所有顶点都包含在S中。

//核心代码:
void  Dijkstra(int  s,int t)//s为起点
{//t为终点
    int temp, k;
    ans=-1;
    for (int i=0; i<n; i++)//对起点邻点操作
    {
        dis[i]=map[s][i];
        vis[i]=0;
    }
    dis[s]=0;
    vis[s]=1;//说明s点已被标记
for (int i=0; i<n; i++)
    {
        temp = inf;//inf为超大的数
        for (int j=0; j<n; j++)
        {
if(vis[j]==0 && temp > dis[j])
            {//j没有被标记且是已知点最小的
                k=j;
                temp=dis[j];
            }
        }
        if(temp == inf) //说明全被标记
            break;
        vis[k]=1;
        for (int j=0; j<n; j++)
        {//看通过k点是否会取得更小值
            if(dis[j] > dis[k] + map[k][j])
                dis[j]=dis[k]+map[k][j];
        }
    }
    if(dis[t]!=inf)
        ans = dis[t];
}


传统dijkstra的不足之处:
(1)用邻接矩阵arcs来存储网络图,其存储量为
NxN。对于大型稀疏矩阵,这将耗费大量资源存储那些
无意义的矩阵元素。
(2)当从未标记节点集合T选定下一个节点vj作
中间节点后,在更新操作过程中,需要扫描所有的未标
记节点并进行比较更新。而未标记节点集合T中往往
包含大量与中间节点V;不直接相连的节点。
(3)在选择下一个最短路径节点作为中间节点时,
需要比较所有的未标记节点。而这个中间节点往往包含
在与已标记节点S集合的所有节点邻接的节点中。
(4)在算法的每次迭代中,由于未标记节点以无序
的形式存放在一个链表中或一个数组中.每次选择最短
路径节点都必须将所有未标记节点扫描一遍,当节点数
目很大时,这无疑将成为制约计算速度的关键冈素。



基于优先队列的优化

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<stack>
#include<queue>
#include<vector>
using namespace std;


#define INF  0x3f3f3f3f   //定义一个很大的数  


struct Node
{
    int num,val;   //存放结点编号和到初始点的距离
} nod;


priority_queue<Node> qq;;   //优先从小到大


bool operator < (Node a,Node b)
{
    if(a.val == b.val) return a.num>b.num;
    return a.val>b.val;              //先出小
}


int book[100];  //检查这个点是否用过
int dis[100];     //到原点最短距离
int D[100][100];  //记录路径长度
int V,E;


int main()
{
    int a,b,d;
    while(cin>>V>>E && V&& E)  //输入顶点数和边数
    {
        while(!qq.empty()) qq.pop(); //清空
        memset(book,0,sizeof(book));
        memset(D,-1,sizeof(D));

        for(int i=0; i<E; i++)
        {
            cin>>a>>b>>d;
            D[a][b] = D[b][a] = d;
        }

        for(int i=2; i<=V; i++)
            dis[i]=INF;

        dis[1]=0;
        nod.num=1;
        nod.val=0;

        qq.push(nod);   //将起点放入队列

        while(!qq.empty())  //不为空时
        {

            for(int i=2; i<=V; i++)
            {
                if(D[qq.top().num][i] != -1  &&dis[i]>dis[qq.top().num] + D[qq.top().num][i])
                {

                    dis[i]=dis[qq.top().num] + D[qq.top().num][i];
                    nod.num=i;
                    nod.val=dis[i];
                    qq.push(nod);
                }
            }

            qq.pop();
        }

        for(int i=1; i<=V; i++)
        {
            cout<<"初始点到"<<i<<"点的距离为:"<<dis[i]<<endl;
        }

    }
    return 0;
}

完全优化后空间复杂度可以从O(N*N)到O(4*N+E),时间复杂度可以从O(N*N)到O(n*(logN+E),具体复杂度分析不在此解析,详情可见参考论文。
在此只是在时间复杂度上有一定的优化,空间复杂度的优化可以用邻接表进行对边的存储。堆优化以及空间优化将在后续更新。




本文参考:王战红1 孙明明2姚 瑶3《Dijkstra算法的分析与改进》的论文。


### Dijkstra算法解释 #### 原理概述 Dijkstra算法是一种用于解决单源最短路径问题的贪心算法,适用于边权重非负的情况。该算法旨在找到加权图中从起始顶点到其他所有顶点之间的最短距离[^2]。 对于每一个被处理过的节点v来说,在未访问集合中的任意邻居w而言,如果通过当前节点到达它的总花费更少,则更新这个最小估计值并记录前驱信息以便后续重建最优路线;当所有的邻接点都被考察完毕之后就将其标记为已访问状态不再重复考虑。此过程持续迭代直到遍历完整张网络结构为止。 #### 实现细节 为了提高效率,通常采用优先队列来选取下一个待扩展的最佳候选者——即具有最低临时成本估算值得结点作为新的起点继续探索未知区域内的连接关系。下面给出了一种常见的Python语言版本的具体编码形式: ```python import heapq def dijkstra(graph, start): pq = [(0, start)] # Priority Queue (cost, node) visited = set() min_dist = {start: 0} while pq: dist_u, u = heapq.heappop(pq) if u in visited: continue visited.add(u) for v, weight_uv in graph[u].items(): alt = dist_u + weight_uv if v not in min_dist or alt < min_dist[v]: min_dist[v] = alt heapq.heappush(pq, (alt, v)) return min_dist ``` 这段程序定义了一个名为`dijkstra()` 的函数接收两个参数:一个是表示图形数据结构的对象 `graph` ,另一个是指定出发位置的关键字 `start`. 它返回一个字典类型的对象 `min_dist`, 其键代表各个目标地点而对应的值则存储着由初始位移至相应终点所需的最少行程长度. 值得注意的是,上述实现假设输入图为邻接表的形式,并且每条边上都附带有一个正实数值用来衡量两者间直接相连所耗费的成本大小。此外还利用了标准库模块`heapq` 来构建一个小根堆从而实现了二叉树型式的优先级序列管理机制以支持快速检索操作。 #### 应用场景 除了经典的交通导航系统中外,Dijkstra算法还在许多领域有着广泛的应用,比如计算机网络路由选择、社交网络分析以及资源分配优化等问题上均能见到其身影。特别是当涉及到求解静态环境下两点间的最佳传输方案时尤为适用[^3].
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值