Dijkstra算法原理与实现

本文详细介绍了迪杰斯特拉算法(Dijkstra算法),该算法由荷兰计算机科学家狄克斯特拉提出,用于解决有权图中最短路径问题。文章通过实例展示了算法的流程,包括初始化、伪代码及C++实现,并强调了算法只适用于不存在负权值边的图。同时,提供了关键函数的实现细节,帮助读者理解并应用Dijkstra算法。

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

目录

前言

一、用途

二、原理与实现

1.流程

2.伪代码

3.代码

三、参考文献


前言

        迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。

        其原理这个动态图可以做出解释:


一、用途

        Dijkstra算法:用来解决单源最短路问题。给定图G和起点s,通过算法得到S到达其他每个顶点的最短距离。

        限制条件:图G中不存在负权值的边。

二、原理与实现

1.流程

步骤1.1,比如说现在有这样一张 5 个点的图(起点是 1):

        下面的 d i s 数组表示现在每个点到起点的距离,因为其他点一开始都不知道,所以我们需要初始化成一个比较大的数。

        那么一开始离起点最近的肯定就是起点自己啦,于是用点 1进行一次更新,点 2 , 3 会被更新。

步骤1.2

 

        为了方便,我们将1号点标成绿色,表示这个点已经用过了。

        那么现在能用的点有: 2 , 3 , 4 , 5,其中离起点最近的是点 3。然后用点 3进行一次更新,点 4 , 5会被更新。

步骤1.3

 

        现在能用的有: 2 , 4 , 5,离起点最近的是点 2。

        用点2 进行一次更新,点 4 会被更新,而点 3 并不会,因为 d i s [ 3 ] < d i s [ 2 ] + 2 。

步骤1.4

 

        现在能用的有: 4 , 5,离起点最近的是点 4。

        用点 4 进行一次更新,没有点会被更新。

        最后用点 5也更新不了其他点,于是我们就这样求出了起点到每个点的最短路。

2.伪代码

Dijkstra(G, d[], s)
{
     初始化;
     for(循环n次)
     {
          u = 使d[u]最小的还未被访问的顶点的标号;
          记u已被访问;
          for(从u出发能到达的所有顶点v)
          {
               if(v未被访问 && 以u为中介点使s到顶点v的最短距离d[v]更优)
               {
                    优化d[v];
               }
          }
     }
}

3.代码

主循环

void Dijkstra(const int x, const int y)
{
    openlist.clear();
    closelist.clear();
    openlist.push_back(x);
    plan_ways_map[x]->G = 0;
    plan_ways_map[x]->H = 0;
    plan_ways_map[x]->F = Calculatef(x);
    while(!openlist.empty())
    {
        int minidnode = Findleastf(openlist);

        openlist.remove(minidnode);
        closelist.push_back(minidnode);

        std::vector<int> candiates = Getnextnode(minidnode);
        for(int i = 0; i < candiates.size(); ++i)
        {
            if(!Isinlist(candiates[i], openlist))
            {
                plan_ways_map[candiates[i]]->parent = minidnode;
                plan_ways_map[candiates[i]]->G = Calculateg(x, candiates[i]);
                plan_ways_map[candiates[i]]->H = 0;
                plan_ways_map[candiates[i]]->F = Calculatef(candiates[i]);
                openlist.push_back(candiates[i]);
            }else{
                double tempg = Calculateg(x, candiates[i]);
                if(tempg > plan_ways_map[candiates[i]]->G)
                {
                    continue;
                }else{
                    plan_ways_map[candiates[i]]->parent = minidnode;
                    plan_ways_map[candiates[i]]->G = tempg;
                    plan_ways_map[candiates[i]]->F = Calculatef(candiates[i]);
                }
            }

            if(Isinlist(y, openlist))
            {
                plan_ways_map[y]->parent = minidnode;
                std::cout << "---------------------------------------------------" << std::endl;
                std::cout << "find!" << std::endl;
                int i = y;
                while(i != -1)
                {
                    plan_path.push_back(i);
                    i = plan_ways_map[i]->parent;
                }
                std::reverse(plan_path.begin(), plan_path.end());
                isfindpath = true;
                return;
            }
        }
    }
    std::cout << "---------------------------------------------------" << std::endl;
    std::cout << "not find" << std::endl;
    return;
}

其他函数

//计算起点到当前点的代价
double Calculateg(const int x, const int idg) const 
{

}

//计算总代价,预置A*接口,Dijkstra相当于简化版A*
double Calculatef(const int idf) const 
{
    
}

//从list中找出总代价的点
int Findleastf(const std::list<int> &listx) const 
{

}

//从当前索引idx找到可行的下一点集合
std::vector<int> Getnextnode(const int idx) const 
{

}

//判断x点是否在list中
bool Isinlist(const int x, const std::list<int> &listx) const 
{

}

三、参考文献

1.迪杰斯特拉算法详解_Hypoc_的博客-优快云博客_迪杰斯特拉算法

2.C++ 求最短路径问题之Dijkstra算法(一)_YF_Li123的博客-优快云博客_c++最短路径算法

讲解 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; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值