《floyd》(邻接矩阵实现)&&《Dijkstra》(邻接表实现) 求最短路径c++

本文介绍了Floyd和Dijkstra两种图算法,详细讲解了它们的实现过程,并提供了C++代码示例。在学习过程中,作者提到了容易混淆的Prime和Kruskal算法,并通过实例演示了Floyd算法寻找最短路径的过程,以及Dijkstra算法的邻接表实现。文章还展示了两种算法的运行结果,帮助读者理解算法的运作机制。

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

枯木逢春不再茂,年少且惜镜边人

今天学习了Floyd 和 dijkstra算法   主要是两种理想的学习

但是在学习这两种思想的时候非常容易和之前学过的prime 和kruskal算法搞混!
所以 接下来复习prime 和kruskal算法

多的不说 直接上代码 具体看代码注释 !!!

*=====>floyd算法*

#include<iostream>
using namespace std;
typedef struct floyd{
    int map[100][100];  //存储邻接矩阵
    int path[100][100]; //Path存储 从  I  -  J    需要通过某个中介点   如果i-j直达则  path存储 i   没有直达也没有中介点相连则 为-1
    int pa[100];  //用来最后输出路径
    int vexnums;  //存储图的节点个数
    int rodenums;  //存储路径条数
}FD;
void init(FD &f) {   //初始化
    for (int i = 0; i < f.vexnums; ++i) {
        for (int j = 0; j < f.vexnums; ++j) {
            if (i==j) {     //如果I==J则 MAP = 0 path为I
                f.map[i][j] = 0;
                f.path[i][j] = i;
            }else {  //否则 map为999999 而Path则初始化为没有任何路径  -1
                f.map[i][j]=999999;
                f.path[i][j]=-1;
            }
        }
    }
}
void FLD(FD &f){
    for (int i = 0; i < f.vexnums; ++i) {
        for (int j = 0; j < f.vexnums; ++j) {
            for (int k = 0; k < f.vexnums; ++k) {
                if (f.map[j][i]!=999999&&f.map[i][k]!=999999&&f.map[j][k]>f.map[j][i]+f.map[i][k]){
                    f.map[j][k]=f.map[j][i]+f.map[i][k];
                    f.path[j][k]=f.path[i][k];
                }
            }// if 里面的条件是FLOYD的核心  也就是map[j][k]>map[j][i]+map[i][k]
        }//其中它的隐式条件是I!= J  I!=K   J!=K
    }
}//floyd结束

void print(FD &f,int start  ,int end){ //打印函数   有个技巧
    int i=0,temp=end;  //先把终点给temp
    while (temp!=start){  //判断temp是不是起点
        f.pa[i++]=temp;  //不是起点如果是终点先加入路径  也可能是start ---end 的中介点  先加入路径
        temp=f.path[start][temp];  //然后判断start ---temp 的中介点
    }//继续判断  知道找到start 和temp直达的那条边  这也就是path矩阵的存储遍历
    f.pa[i++]=start;  //把start入到pa中去
    cout<<start<<"到"<<end<<"的最短路径是 : "<<endl;
    for (int j = i-1; j >0 ; --j) {  //开始遍历
       cout<<f.pa[j]<<"->";
    }
    cout<<f.pa[0]<<endl;
}
int main(){
   FD f;
   int start,end,len;
   cout<<"请输入路径上的节点数和边数"<<endl;
   cin>>f.vexnums>>f.rodenums;
   init(f);
   cout<<"请输入每条路径的 起始点  终点  和  权值 "<<endl;
    for (int i = 0; i < f.rodenums; ++i) {   //创建邻接矩阵
        cin>>start>>end>>len;
        f.map[start][end]=len;
        f.map[end][start]=len;
        f.path[start][end]=start;
        f.path[end][start]=end;
    }
    cout<<"请输入起点和终点!"<<endl;
    cin>>start>>end;
    FLD(f);
    if (f.map[start][end]==999999){
        cout<<"-1"<<endl;
    }else{
        cout<<f.map[start][end]<<endl;
        print(f,start,end);
    }
}

测试结果

请输入路径上的节点数和边数
5 5
请输入每条路径的 起始点  终点  和  权值
0 1 2
1 2 2
2 3 3
3 4 4
1 4 5
请输入起点和终点!
0 4
7
04的最短路径是 :
0->1->4

具体 Path如何遍历 可以看看下图

 半年后0

下面就是Dijkstra的算法实现

请看代码

#include<iostream>
#include <limits>
using namespace std;
struct edgnode{  //边节点的结构体
    int adjindex;  //改变节点的下标
    int weight;    // 权值
    edgnode *next;
};
struct Head{
    int  nodeinfo;  //节点信息
    int  indegree;  //节点入度
    int  value;    //当前到起点的权值
    bool change;   //当前节点是否被选
    int parent;    //当前节点的双亲
    edgnode *firstnode;
};
void creatnextlist(Head *G,int vexnums,int edgnums){ //创建邻接表
    for (int i = 0; i < vexnums; ++i) {
        G[i].nodeinfo=i+1;  //使Vi  从v1开始
        G[i].indegree=0;    //入度 为0   该算法中无用
        G[i].firstnode=NULL;
    }
    cout<<"请输入边的起点 终点 和 权值"<<endl;
    for (int i = 0; i < edgnums; ++i) {  //类似头插法建立邻接矩阵  有向网
        int start ,end ,weight;
        cin>>start>>end>>weight;
        edgnode *node=new edgnode;
        node->adjindex=end-1;
        node->weight=weight;
        node->next=G[start-1].firstnode;
        G[start-1].firstnode=node;
    }
}
int getweight(Head *G,int start ,int end){  //获得 start  --end 的权值
    edgnode *node =G[start-1].firstnode;  //注意下标和实际数字的区别
    while (node){
        if (node->adjindex==end-1){  //找到start 直连的那个边  获得其权值
            return  node->weight;
        }
        node = node->next;  //继续找
    }
}

void dijkstra(Head *G,int vexnums,int start){   //算法开始
    for (int i = 0; i < vexnums; ++i) {
        G[i].value=INT_MAX;  //一开始都没有路径连接  所以设置最大值
        G[i].change=false;  //全部设置为未选
    }
    G[start-1].value=0;  //起点 初始化
    G[start-1].parent=-1;
    while (true){
        bool  flag= true;  //设置flag  判断节点是否全部被选
        for (int i = 0; i < vexnums; ++i) {
            if (!G[i].change){  //没有被全部选中则就继续选择节点  flag=false
                flag= false;
                break;
            }
        }
        if (flag){  //如果全部选中  则表示选择结束  算法结束直接返回
            return ;
        }
        int min=-1;     //每次遍历结构体  找到到起点权值最小的节点
        for (int i = 0; i < vexnums; ++i) {
            if (!G[i].change){
                if (min==-1){
                    min=i;
                }else{
                    if (G[min].value>G[i].value){
                        min=i;
                    }
                }
            }
        }  //找到后 min为找到的那个
        cout<<"当前选中节点是V"<<min+1<<endl;
        G[min].change=true;  //标记选中
        edgnode *node= G[min].firstnode;  //开始找他直达的边
        while (node){
            int begin =  min+1;   //G[min].nodeinfo+1
            int end = node->adjindex+1; 
            int weight =getweight(G,begin,end); //得到权值
            if (weight+G[min].value<G[node->adjindex].value){  //判断起点到当前节点的路径长度是不是小于之前找的路径长度(直接更新)  或是之前没有找到  则直接赋值
                G[node->adjindex].value=weight+G[min].value; //更新该值
                G[node->adjindex].parent=min;//记录父亲  方便以后遍历用
            }
            node=node->next;
        }
    }
}
void print(Head *G , int k){  //利用递归的思想遍历  因为从最后查  父亲 然后 就  先查出的后输出
    if (G[k-1].parent==-1){   //找到起点了  开始输出
        cout<<"v"<<k;
    }else if(k!=0){
        print(G,G[k-1].parent+1);  //K不是起点 则继续找他的父亲
        cout<<" ->v"<<k;
    }
}
int main(){
    Head *G;
    int vexnums,edgnums;
    cout<<"请输入节点的个数  和  边数"<<endl;
    cin>>vexnums>>edgnums;
    G = new Head[vexnums]; //结构体数组
    creatnextlist(G,vexnums,edgnums);

    dijkstra(G,vexnums,1);
    for (int i = 2; i <=vexnums ; ++i) {
        cout<<"v1到V"<<i<<"的最短路径长度是"<<G[i-1].value<<endl;
        print(G,i);
        cout<<endl;
    }
};

运行结果

请输入节点的个数  和  边数
5 5
请输入边的起点 终点 和 权值
1 2 2
2 3 2
3 4 3
4 5 4
2 5 5
当前选中节点是V1
当前选中节点是V2
当前选中节点是V3
当前选中节点是V4
当前选中节点是V5
v1到V2的最短路径长度是2
v1 ->v2
v1到V3的最短路径长度是4
v1 ->v2 ->v3
v1到V4的最短路径长度是7
v1 ->v2 ->v3 ->v4
v1到V5的最短路径长度是7
v1 ->v2 ->v5

Process finished with exit code 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值