用c++实现基于vector的迪杰斯特拉算法

本文介绍了一种基于Linux环境下的迪杰斯特拉最短路径算法实现,通过使用C++编程语言,详细展示了如何构建图的数据结构并计算两点间的最短路径。

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

本程序的实现是在linux redhat,vmware下实现的,使用的是g++编译器,如何读者使用其他的编译器,可能需要小改一下代码~~

#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
#include<sstream>
#define INF 1147483646
#define maxn 50
using namespace std;

vector<int> edges[maxn];//the edges

struct Point{
  string name;
  int num;
  Point(string name,int num):name(name),num(num){}
};

struct mp{
  int pn;
  vector<Point> point;
  vector<int>* e;
mp(vector<Point> point,vector<int>* e):point(point),e(e),pn(point.size()){}
};

struct Trace{      //trace
  vector<Point> point;
  int length;
  int num;  //dest point num
  Trace(int length=INF,int num=0):length(length),num(num){}
  Trace& operator = (const Trace& B)
  {
    this->point=B.point;
    this->length=B.length;
    this->num=B.num;
  }
};

void fangyi(int& a)
{
  if(a>INF)
  a=INF;
}
void inputpoint(vector<Point>& point)
{
  printf("Please input the points:\n");
  printf("Input quit to end input data.\n");
  string a;
  int i=0;
  while(cin>>a)
  {
    if("quit"==a)
    break;
    point.push_back(Point(a,i++));
  }
}
int findpnum(const vector<Point>& ps,string s)
{
  int i=0;
  while(i<ps.size())
  {
    if(s==ps[i].name)
    break;
    i++;
  }
  if(i>=ps.size())
  return -1;
  return i;
}

void inputedge(const vector<Point>& ps)
{
  printf("Please input the edge format as:start point end point value:\n");
  printf("Input quit to end input data.\n");
  string a;
  string st,en;
  int va,tt;
  for(int i=0;i<ps.size();i++)     //create the edges
   for(int j=0;j<ps.size();j++)
   {
     if(i==j)
       edges[i].push_back(0);
     else
       edges[i].push_back(INF);

   }
  while(getline(cin,a))
  {
    if("quit"==a)
    break;
    stringstream s(a);
    s>>st;
    s>>en;
    s>>va;
    if(s>>tt)
    {
      printf("input error,again!\n");
      continue;
    }
    int stnum=findpnum(ps,st);
    int ennum=findpnum(ps,en);
    if((-1==stnum)||(-1==ennum))
    {
      printf("the point is not exit!\n");
      continue;
    }
    edges[stnum][ennum]=va;
    edges[ennum][stnum]=va;
  }
}

void djstl(const mp& map,vector<Trace>& t)
{
  string s,e;
  int sn,en;
  printf("Input the start point and the end point:\n");
  cin>>s>>e;
  sn=findpnum(map.point,s);
  en=findpnum(map.point,e);
  for(int j=0;j<map.pn;j++)
  {
    t.push_back(Trace(INF,j));//create trace for each point
    t[j].point.push_back(Point(map.point[sn].name,sn));
    t[j].point.push_back(Point(map.point[j].name,j));
    t[j].length=map.e[sn][j];
  }
  for(int i=1;i<map.pn;i++)
  for(int i=1;i<map.pn;i++)
  {
    for(int j=1;j<map.pn;j++)//sort from min to max
    {
       int m=j;
       if(t[m].length<t[m-1].length)
       {
       Trace tmp=t[m];
       while(m>0)
       {
          if(tmp.length>=t[m-1].length)
            break;
          t[m]=t[m-1];
          m--;
       }
       t[m]=tmp;
       }
    }

    for(int k=i+1;k<map.pn;k++) //base on the i element
    {
      int sn=t[i].num;
      int en=t[k].num;
      int len=t[i].length+map.e[sn][en];//overflow!
      fangyi(len);
      if(len<t[k].length)//shorter than trace through t[i]
      {
        int tm=t[k].num;
        t[k]=t[i];
        t[k].num=tm;
        t[k].point.push_back(Point(map.point[tm].name,tm));
        t[k].length=len;
      }
    }
  }
  int j,q;
  for(j=0;j<t.size();j++)
    if(en==t[j].num)
      break;
  for(q=0;q<t[j].point.size()-1;q++)
  {
  {
    cout<<t[j].point[q].name<<"->";
  }
  cout<<t[j].point[q].name<<endl;
  cout<<"The whole length is"<<t[j].length<<endl;
}
int main()
{
  vector<Point> p;
  vector<Trace> t;//the start point to others' trace
  inputpoint(p);
  inputedge(p);
  mp m(p,edges);
  djstl(m,t);
  return 0;
}
迪杰斯特拉算法概括起来就是,先找出起点到终点直接连接的长度,然后对长度排序(从小到大),然后以小的长度的路径间接构造到后面比较的节点的路径,因为如果存在b,使得a+b<c,那么只有当a<c时才存在(假设图为正权值的图)。外循环n-1次,每次以当前节点为间接构造的基本点。内循环n-k-1次,k为当前要找的更短路径的目的节点。

假设有图如下所示:


那么输入的计算的步骤是这样的:


可见,程序运行是没有问题的~~

注:要提醒读者的一点是,vector在还没有使用push_back()函数创建元素时,是不能对元素进行复制的,此时访问的是非法内存。



<think>嗯,用户想了解C++和C语言如何实现迪杰斯特拉算法。首先,我需要回忆一下迪杰斯特拉算法的基本原理,确保自己理解正确。迪杰斯特拉是用于在图中找到单源最短路径的算法,适用于带权重的有向或无向图,且权重必须非负。对吧?所以关键点包括优先队列(或最小堆)的使用,以及每次选择距离起点最近的节点进行松弛操作。 接下来,用户可能需要对比C和C++实现差异。C++可以利用STL中的优先队列,而C语言则需要手动实现最小堆或者使用数组来模拟。这可能会导致代码结构和复杂度的不同。我需要分别考虑两种语言的特点,比如C++的面向对象特性是否会被用到,或者C语言中结构体和函数指针的使用。 然后,用户可能关心代码的结构和步骤。需要分步骤解释,比如初始化距离数组,设置优先队列,循环处理节点,松弛边等。对于C++,使用STL的priority_queue会简化代码,而C则需要手动管理堆结构,这可能增加代码量。 同时,要注意代码示例的正确性。比如在C++中,优先队列默认是最大堆,所以需要传入比较函数或使用负数来模拟最小堆。而在C语言中,可能需要一个数组来维护未处理的节点,或者每次遍历查找最小距离节点,这样时间复杂度会更高,但适合教学目的。 还需要考虑用户可能的疑问,比如为什么迪杰斯特拉算法需要权重非负,如何处理负权边的情况,这时候可能需要提到贝尔曼-福特算法。不过用户的问题集中在实现,所以这部分可能作为额外补充。 另外,代码的可读性很重要,变量命名要清晰,注释要到位。例如,在C语言实现中,手动实现的优先队列或选择最小节点的逻辑需要详细解释,而C++的STL部分可以更简洁。 可能还需要比较两种实现的效率。C++的优先队列实现通常是O((V+E) log V),而C语言如果使用数组找最小节点的话是O(V²),更适合稠密图。但用户可能更关注实现方式而非性能差异,所以需要指出两者的适用场景。 最后,总结两者的异同,强调C++的便捷性和C语言的底层控制,满足不同需求。检查是否存在语法错误,比如在C语言中结构体的使用,内存分配是否正确,循环条件是否合理。确保代码示例符合用户提供的系统级指令,比如数学公式的格式是否正确,使用$$包裹独立公式等。 现在需要组织这些思考点,分步骤解释迪杰斯特拉算法实现,并提供C和C++代码示例。确保代码正确,注释清晰,同时对比两者的实现方式,帮助用户理解不同语言下的处理方式。</think>迪杰斯特拉算法(Dijkstra's Algorithm)是解决**单源最短路径问题**的经典算法,适用于带非负权重的有向/无向图。以下分步骤说明C++和C语言的实现差异,并附代码示例。 --- ### 一、算法核心步骤 1. **初始化**:设置距离数组`dist[]`,起点距离为0,其他为无穷大。 2. **优先队列**:存储未处理的节点及其当前最短距离。 3. **贪心选择**:每次从队列中取出距离最小的节点`u`。 4. **松弛操作**:遍历`u`的邻接节点`v`,若`dist[u] + weight(u,v) < dist[v]`,则更新`dist[v]`。 5. **重复**直到所有节点处理完毕。 --- ### 二、C++实现(利用STL优先队列) ```cpp #include <vector> #include <queue> #define INF 0x3f3f3f3f using namespace std; typedef pair<int, int> pii; // (distance, node) void dijkstra(vector<vector<pii>>& graph, int start, vector<int>& dist) { priority_queue<pii, vector<pii>, greater<pii>> pq; // 最小堆 dist[start] = 0; pq.push({0, start}); while (!pq.empty()) { int u = pq.top().second; int curr_dist = pq.top().first; pq.pop(); if (curr_dist > dist[u]) continue; // 已找到更优路径,跳过 for (auto& edge : graph[u]) { int v = edge.first, weight = edge.second; if (dist[u] + weight < dist[v]) { dist[v] = dist[u] + weight; pq.push({dist[v], v}); } } } } ``` **关键点**: - 使用`priority_queue`自动维护最小距离节点 - 时间复杂度:$O((V+E)\log V)$(V为顶点数,E为边数) --- ### 三、C语言实现(手动管理节点) ```c #include <stdio.h> #include <limits.h> #define V 6 // 假设图有6个节点 #define INF INT_MAX void dijkstra(int graph[V][V], int start) { int dist[V], visited[V]; for (int i = 0; i < V; i++) { dist[i] = INF; visited[i] = 0; } dist[start] = 0; for (int count = 0; count < V-1; count++) { // 手动选择当前最小距离节点 int u = -1, min_dist = INF; for (int i = 0; i < V; i++) { if (!visited[i] && dist[i] < min_dist) { min_dist = dist[i]; u = i; } } if (u == -1) break; // 剩余节点不可达 visited[u] = 1; // 松弛操作 for (int v = 0; v < V; v++) { if (!visited[v] && graph[u][v] && dist[u] != INF && dist[u] + graph[u][v] < dist[v]) { dist[v] = dist[u] + graph[u][v]; } } } // 输出结果 printf("Vertex\tDistance from Start\n"); for (int i = 0; i < V; i++) printf("%d\t%d\n", i, dist[i]); } ``` **关键点**: - 通过数组`visited[]`和遍历选择最小节点 - 时间复杂度:$O(V^2)$,适合稠密图 --- ### 四、C++与C实现的对比 | 特性 | C++ | C语言 | |---------------------|------------------------------|---------------------------| | 优先队列管理 | 使用STL的`priority_queue` | 手动遍历选择最小节点 | | 时间复杂度 | $O((V+E)\log V)$ | $O(V^2)$ | | 代码简洁性 | 更简洁(自动内存管理) | 需要手动处理细节 | | 适用场景 | 稀疏图 | 稠密图或小规模图 | --- ### 五、注意事项 1. **负权重**:迪杰斯特拉算法无法处理含负权边的图,需改用Bellman-Ford算法。 2. **路径记录**:可添加`prev[]`数组记录路径前驱节点。 3. **堆优化**:C语言可通过手动实现最小堆优化到$O((V+E)\log V)$。 两种实现各有优劣,C++版本适合快速开发,C版本则更贴近底层控制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值