图的最小生成树及最短路径算法

图的最小生成树算法及最短路径算法

——Prim算法,Dijkstra算法及Floyd算法

概述

我的上一篇博客图的DFS与BFS(C++)中谈到了用C++实现图的构建和遍历。这次,我仍然准备构建储存结构为邻接矩阵的无向图,来实现求图的最小生成树的Prim算法,求图单源最短路径的Dijkstra算法,以及求图多源最短路径的Floyd算法。其实求最小生成树还有一种Kruskal算法,但因为此例用邻接矩阵储存,不方便表达边与两个邻接点及权值的关系,故之后我会另开一篇叙述。

代码

1.引入必要头文件,对图的抽象数据类型进行声明。这里定义3个接口,分别对应用于实现3个算法。

#include<iostream>
#include<vector>
#include<mem.h>
int inf=9999;
using namespace std;

//Graph为封装的类模板
template <class T>
struct Graph{
    //储存顶点
    vector<T> vertex;
    //储存边
    vector<vector<int>> edge;
    //标记数组
    bool book[100];
    Graph(int n,int m);
    ~Graph();
    void Prim(int cur);
    void Dijkstra(int cur);
    void Floyd();
};

2.图的构造函数和析构函数:

template <class T>
 Graph<T>::Graph(int n,int m){
    vertex.resize(n+1);
    edge.resize(n+1);
    for(int i=0;i<n+1;i++){
    edge[i].resize(n+1);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==j) edge[i][j]=0;
            else edge[i][j]=inf;
        }
    }
    cout<<"请依次输入各条边的两个邻点及权值(无向)"<<endl;
    for(int i=1;i<=m;i++){
        int a,b,c;
        cin>>a>>b>>c;
        edge[a][b]=edge[b][a]=c;
    }
    cout<<endl;
    for(int i=1;i<=n;i++){
        vertex[i]=i;  //顶点值用编号赋值,方便理解
    }
    memset(book,0,100);
}

template <class T>
Graph<T>:: ~Graph(){
    vertex.clear();
    edge.clear();
}

3.Prim算法实现

template <class T>
void Graph<T>::Prim(int cur){
    vector<int> dis(vertex.size());
    for(int i=1;i<=vertex.size()-1;i++){
        dis[i]=edge[cur][i];
    }
    //表示1号顶点已加入最小生成树
    int count=1;  
    cout<<vertex[cur]<<"——";
    book[cur]=1;
    int sum=0;
    while(count<vertex.size()-1){
        int min=inf;
        int j;
        for(int i=1;i<=vertex.size()-1;i++){
            if(book[i]==0&&dis[i]<min){   
                min=dis[i];
                j=i;
            }
        }
        cout<<vertex[j];
        sum += dis[j];
        book[j]=1;
        for(int k=1;k<=vertex.size()-1;k++){
            if(book[k]==0&&edge[j][k]<dis[k]){
                dis[k]=edge[j][k];
            }
        }
        count++;
        if(count<vertex.size()-1) cout<<"——";
    }
    cout<<endl;
    cout<<"最小生成树权值和为:"<<sum<<endl;
}

4.Floyd算法实现

template <class T>
void Graph<T>::Floyd(){
    /*设下标为k的顶点为从i到j的路径中途可能经过的点
    如果该点而能使i到j路径收缩,则更新i到j路径 */
    for(int k=1;k<=vertex.size()-1;k++){
        //i,j为任意路径的起始点和终点
        for(int i=1;i<=vertex.size()-1;i++){
            for(int j=1;j<=vertex.size()-1;j++){
                //路径收缩
                if(edge[i][k]+edge[k][j]<edge[i][j]){
                    edge[i][j]=edge[i][k]+edge[k][j];
                }
            }
        }
    }
    //打印出任意两点间的最短路径
    for(int i=1;i<=vertex.size()-1;i++){
        for(int j=1;j<=vertex.size()-1;j++){
            if(edge[i][j]<inf&&edge[i][j]!=0){
                cout<<i<<"->"<<j<<"最短路径长度为 "<<edge[i][j]<<endl;
            }
        }
    }
}

5.Dijkstra算法实现

template <class T>
void Graph<T>::Dijkstra(int cur){
    vector<int> dis(vertex.size());
    for(int i=1;i<=vertex.size()-1;i++){
        dis[i]=edge[cur][i];
    }
    int j;
    
    //表示1号顶点已加入路径确定的集合中
    book[1]=1;
    while(count<vertex.size()-1){
        int min=inf;
        for(int i=1;i<=vertex.size()-1;i++){
            if(book[i]==0&&dis[i]<min){  
                min=dis[i];
                j=i;
            }
        }
         book[j]=1;  
        for(int k=1;k<=vertex.size()-1;k++){
            if(edge[j][k]+dis[j]<dis[k]&&edge[j][k]<inf){  
                dis[k]=dis[j]+edge[j][k];
            }
        }
        count++;
    }
    for(int i=1;i<=vertex.size()-1;i++){
        cout<<cur<<"->"<<i<<"最短路径长度为"<<dis[i]<<endl;
    }
}

6.最后,main函数实例化图对象,调用对象方法,实现算法。(注意:每次调用用函数接口后要将标记数组重新初始化为0)

int main(){
    Graph<int>* G=new Graph<int>(5,5);

    cout<<"Prim算法求最小生成树如下:"<<endl;
    G->Prim(1);
    memset(G->book,0,100);
    cout<<endl;

    cout<<"Dijkstra算法求单源最短路径如下:"<<endl;
    G->Dijkstra(1);
    memset(G->book,0,100);
    cout<<endl;

    cout<<"Floyd算法求任意两点最短路径如下:"<<endl;
    G->Floyd();
    cout<<endl;
     
    system("pause");
    return 0;
}

输出

控制台输出结果
控制台输出结果

posted @ 2019-04-11 22:12  orion-orion  阅读(544)  评论(0编辑  收藏  举报