C++实现图的最短路径算法总结--floyd算法、Dijkstra算法以及bellman-Floyd算法

  一、Floyd算法

       首先是Floyd算法,这种算法思路是最简单的,但是相对于来说,时间复杂度就高一些,这种方法核心思想就是不断进行边松弛优化,主要代码如下;

void Floyd(vector<vector<int>> &adjucent, int n) {                  //adjucent是邻接矩阵,n是点个数
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            for (int k = 0; k < n; ++k) {
                if (adjucent[j][k] > adjucent[j][i] + adjucent[i][k])
                    adjucent[j][k] = adjucent[j][i] + adjucent[i][k];
            }
        }
    }
}

时间复杂为O(n^3),这种方法适合多源最短路径,如果对时间复杂度有要求,可以参考dijkstra算法

二、Dijkstra算法

Dijktra算法,时间复杂度为O(n^2),依靠邻接矩阵,单源最短路径算法,但是这里未进行优化

#define INF INT_MAX

//adjucent为邻接矩阵、n为点个数、begin为起点,dist保存begin到各个点的最短路径,visit记录是否访问
void Dijkstra(vector<vector<int>> &adjucent, int n, int begin, int dist[],int visit[]) {   
    for (int i = 0; i < n; ++i) {
        dist[i] = adjucent[begin][i];
    }
    visit[begin] = 1;
    for (int i = 0; i < n; ++i) {
        int min = INF, index = 0;
        for (int j=0; j < n; ++j) {
            if (visit[j] == 0 && dist[j] < min) {                 //找出每一个最小点,进行边松弛优化
                min = dist[j];
                index = j;
            }
        }
        if (min != INF) {
            visit[index] = 1;
            for (int j = 0; j < n; ++j) {
                if (adjucent[index][j] + adjucent[begin][index] <dist[j])                //边松弛优化
                    dist[j] = adjucent[index][j] + adjucent[begin][index];
            }
        }
    }
}

可以看见,上述在寻找每一次的最小点的时候,都会浪费更多时间去寻找,因此可以利用堆进行优化,使得时间复杂度为O(nlogn),为了方便,这里直接采用了STL里面的优先队列priority_queue,如果不了解的,可以去参考《STL源码剖析》,采用堆优化,此时就不能依靠邻接矩阵了,可以依靠邻接表,因此总的代码如下:

#define INF INT_MAX

struct node {
    int value;
    int point;
    node(int x,int y):point(x),value(y){}
    bool operator < (const node &a) const {               //因为采用了堆,因此必须重载<运算符建立对应堆
        if (value == a.value) return point < a.point;
        else
            return value > a.value;
    }
};
void Dijkstra_heap(vector<node> edge[],int n,int begin,int dist[]) {
    priority_queue<node> q;
    for (int i = 0; i < n; ++i) {
        dist[i] = INF;
    }
    dist[begin] = 0;
    q.push(node(begin, dist[begin]));
    while (!q.empty()) {
        node Q = q.top();
        q.pop();
        for (int i = 0; i < edge[Q.point].size(); ++i) {
            node y = edge[Q.point][i];
            if (dist[y.point] > y.value + Q.value)
            {
                dist[y.point] = y.value + Q.value;
                q.push(node(y.point, dist[y.point]));
            }
        }
    }
}

三、Bellman-Floyd算法

以上两种办法,都是解决非负权的图,如果出现负值的时候,以上两种办法就不合适了,主要考虑到负权值环的存在,因此需要采用Bellman-Floyd算法,该算法主要还是利用了边松弛,只是,当进行一次遍历后,需要判断是否存在负权值环,如果存在就不可能出现最小值,因此核心代码如下:

//prev[]用来保存寻找路径,dist[]保存最短路径权值,

struct edge
{
    int u, v;
    int val;
};
bool bellman_ford(edge e[], int pre[], int n, int m, int dist[]) {
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            if (dist[e[j].v] > dist[e[j].u] + e[j].val) {
                dist[e[j].v] = dist[e[j].u] + e[j].val;
                pre[e[j].v] = e[j].u;
            }
        }
    }
    int flag = 1;
    for (int j = 0; j < m; ++j) {
        if (dist[e[j].v] > dist[e[j].u] + e[j].val) {
            flag = 0;
            break;
        }
    }
    return flag;
}

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/Mr_fightingboy/article/details/81094393
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞