Dijkstra算法的实现及原理

本文介绍了Dijkstra算法的作用——求解指定点到图中任意点的最短路径。通过对比BFS,阐述了Dijkstra算法的基本思想,并重点讲解了优先队列在算法中的应用。接着,详细描述了算法过程,包括最短路径数组、访问状态数组的初始化,以及如何利用优先队列进行路径更新。最后,提到了使用STL中的`priority_queue`来实现优先队列的细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法用处与基本思想

Dijkstra算法的作用是求指定点到图中任何一点的最短路径。
其基本思路与BFS(深度优先搜索)有些类似,但不同的是BFS用的是一般队列,也就是严格的先进先出。而Dijkstra算法用到的则是优先队列。

什么是优先队列

优先队列中是有序的队列,其顺序取决于规定的规则。比如可以规定值大的在前面,也可以规定值小的在前面。一般来说直接用STL里面的priority_queue来实现,这个默认的是较大的值在前面。

算法过程

有一个保存到每个点最短路径的数组,这里记为shortlen[](默认值为无穷,代表无通路)。还有一个记录点是否被访问过的数组,这里记为visit[]。
一开始,从起点开始,用每一个与起点相连的且没有被访问过的点的距离对shortlen数组进行更新,例如:第i个点与起始点的距离为x,x小于无穷,那么久把shortlen[i]的值更新为x。
只要有通路的点,全部放入优先队列然后把这个点记为被访问过。
然后就从队列里取出队头,将其当做新的起点,重新进行上面的操作。
当队列为空时跳出循环,这个时候的shortlen数组的值就是起点到各个点的最短距离。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
using namespace std;
const int INF=65535;
const int maxn=110;
unsigned int mp[maxn][maxn];
bool visit[maxn];
unsigned int shortlen[maxn];
typedef struct Node{
    int dis,v;
    bool operator < (const Node &cmp) const{//重载小于号,不理解的可以直接用。作用相当于定义一个优先队列的比较规则
        return dis > cmp.dis;
    }
}Node;
void Dijkstra(int start,int num)
{
    int value;
    memset(visit,false,sizeof(visit));
    memset(shortlen,INF,sizeof(shortlen));
    priority_queue<Node> q;
    shortlen[start]=0;
    q.push({0,start});//起点放入队列
    while(!q.empty())
    {
        Node a=q.top();//取出
        q.pop();
        start=a.v;
        value=shortlen[start];
        visit[start]=true;//记为访问过
        for(int i=1;i<=num;++i){
            if(i==start)
                continue;
            if(mp[start][i]<INF&&visit[i]==false){
                    if(mp[start][i]+value<shortlen[i])
                        shortlen[i]=mp[start][i]+value;//更新数组
                    q.push({shortlen[i],i}); 
               }
        }
    }
}
int main()
{
//    freopen("in.txt","r",stdin);
    int numv;
    int x,y,w,v;
    cout<<"InPut the number of v"<<endl;
    cin>>numv;
    memset(mp,INF,sizeof(mp));
    cout<<"Build Map"<<endl;
    while(cin>>x>>y&&(x||y))
    {
        cin>>w;
        mp[x][y]=w;
        mp[y][x]=w;
    }
    cout<<"Input the start"<<endl;
    cin>>v;

    Dijkstra(v,numv);
    for(int i=1;i<=numv;++i)
        cout<<"i="<<i<<" shortlen="<<shortlen[i]<<endl;
    cout<<endl;
    return 0;
}
讲解 Dijkstra 算法的基本思想,另外还有算法实现. 当然了,这个算法当路径点上万的时候效率上会降低。 我有另外的改进实现, 上万个点也是在200毫秒内完成。但是不知道怎么添加, 我只能在这里贴关键代码了 : static std::list<Node*> vecNodes; static std::list<Edge*> vecEdges; bool CDijkstras::DijkstrasFindPath(Node* psrcNode, Node* pdstNode, std::list<Node*>& vec, double& fromSrcDist) { if (psrcNode == 0 || pdstNode == 0) return false; if (psrcNode == pdstNode) { vec.push_back(pdstNode); return false; } std::list<Node*>::const_iterator it; for (it=vecNodes.begin(); it!=vecNodes.end(); it++) { (*it)->bAdded = false; (*it)->previous = 0; (*it)->distanceFromStart = MAXDOUBLE; (*it)->smallest = 0; } bool bFindDst = DijkstrasRouteInitialize(psrcNode, pdstNode); fromSrcDist = pdstNode->distanceFromStart; Node* previous = pdstNode; while (previous) { vec.push_back(previous); previous = previous->previous; } m_pDstNode = pdstNode; return bFindDst; } bool CDijkstras::DijkstrasRouteInitialize(Node* psrcNode, Node* pdstNode) { bool bFindDst = false; psrcNode->distanceFromStart = 0; Node* smallest = psrcNode; smallest->bAdded = true; std::list<Node*>::const_iterator it, ait; std::list<Node*> AdjAdjNodes ; for (it=psrcNode->connectNodes.begin(); it!=psrcNode->connectNodes.end(); it++) { if ((*it)->bAdded) continue; (*it)->smallest = psrcNode; (*it)->bAdded = true; AdjAdjNodes.push_back(*it); } while (1) { std::list<Node*> tempAdjAdjNodes; for (it=AdjAdjNodes.begin(); it!=AdjAdjNodes.end(); it++) { Node* curNode = *it; for (ait=curNode->connectNodes.begin(); ait!=curNode->connectNodes.end(); ait++) { Node* pns = *ait; double distance = Distance(pns, curNode) + pns->distanceFromStart; if (distance < curNode->distanceFromStart) { curNode->distanceFromStart = distance; curNode->previous = pns; } if (pns->bAdded == false) { tempAdjAdjNodes.push_back(pns); pns->bAdded = true; } } if (curNode == pdstNode) { bFindDst = true; } } if (bFindDst) break; if (tempAdjAdjNodes.size() == 0) break; AdjAdjNodes.clear(); AdjAdjNodes = tempAdjAdjNodes; } return bFindDst; } // Return distance between two connected nodes float CDijkstras::Distance(Node* node1, Node* node2) { std::list<Edge*>::const_iterator it; for (it=node1->connectEdges.begin(); it!=node1->connectEdges.end(); it++) { if ( (*it)->node1 == node2 || (*it)->node2 == node2 ) return (*it)->distance; } #ifdef _DEBUG __asm {int 3}; #endif return (float)ULONG_MAX; } /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ //得到区域的Key// __int64 CDijkstras::GetRegionKey( float x, float z ) { long xRegion = (long)(x / m_regionWidth); long zRegion = (long)(z / m_regionHeight); __int64 key = xRegion; key <<= 32; key |= ( zRegion & 0x00000000FFFFFFFF ); return key; } //得到区域的Key// __int64 CDijkstras::GetRegionKey( long tx, long tz ) { long xRegion = tx ; long zRegion = tz ; __int64 key = xRegion; key <<= 32; key |= ( zRegion & 0x00000000FFFFFFFF ); return key; } //取得一个区域内的所有的路径点, 返回添加的路径点的个数// unsigned long CDijkstras::GetRegionWaypoint (__int64 rkey, std::vector<Node*>& vec) { unsigned long i = 0; SAME_RANGE_NODE rangeNode = mmapWaypoint.equal_range(rkey); for (CRWPIT it=rangeNode.first; it!=rangeNode.second; it++) { i++; Node* pn = it->second; vec.push_back(pn); } return i; } inline bool cmdDistanceNode (Node* pNode1, Node* pNode2) { return pNode1->cmpFromStart < pNode2->cmpFromStart; }; //添加一个路径点// Node* CDijkstras::AddNode (unsigned long id, float x, float y, float z) { Node* pNode = new Node(id, x, y, z); __int64 rkey = GetRegionKey(x, z); mmapWaypoint.insert(make_pair(rkey, pNode)); mapID2Node[id] = pNode; return pNode; } //添加一条边// Edge* CDijkstras::AddEdge (Node* node1, Node* node2, float fCost) { Edge* e = new Edge (node1, node2, fCost); return e; } //通过路径点ID得到路径点的指针// Node* CDijkstras::GetNodeByID (unsigned long nid) { std::map<unsigned long, Node*>::const_iterator it; it = mapID2Node.find(nid); if (it!=mapID2Node.end()) return it->second; return NULL; }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值