1. 程式人生 > 其它 >最完整+全解析的Floyd演算法(C++版)

最完整+全解析的Floyd演算法(C++版)

技術標籤:C++c++演算法圖論c語言程式語言

Floyd演算法(完整版解決最短路徑問題)


  本文小述:本文運用鄰接矩陣構造的是有向圖,用鄰接矩陣實現Floyd演算法(有興趣的話可以自己動手用鄰接表的方法嘗試實現以下),在實現的過程中加強了動態陣列的運用。該程式碼配合 B站視訊的講解來看更易懂哦~程式碼是多註釋、完整版(將.cpp和.h的檔案程式碼聯合起來便可完整實現)。

一、Floyd演算法簡介

  Floyd(弗洛伊德)演算法相對於Dijkstra演算法來說,可以解決多源最短路徑問題(即可以從任意一個點到任意一個點),可應用於地圖導航走最短路徑、為各城市修建最短路徑的通訊網(節省成本)等問題,時間複雜度是O(n3

)

二、程式碼部分

知識儲備:動態建立二維陣列、鄰接矩陣、圖論、虛解構函式、靜態函式(static)的運用

Graph.h檔案程式碼

#ifndef GRAPH_H
#define GRAPH_H
#include <algorithm>
#include <stdio.h>	// exit()函式需要用到的標頭檔案
#define X 9999	//相當於無窮大

class Graph
{
    private:
        static Graph* instance;		//建立例項:類是一個抽象類,例項可方便用於調取類成員的方法函式
        int n, m;
//n是頂點個數,m是邊數 char* data; //頂點陣列,用來儲存頂點(char型別) int** w; //weight 邊的權重,鄰接矩陣 int** path; //用來記錄最小邊權值頂點的序號,鄰接矩陣 public: Graph(); virtual ~Graph(); //虛解構函式,用來程式結束後釋放new的記憶體 static Graph* getInstance(); //獲取例項 void createGraph(Graph& G); int
getIndex(const Graph& G, char v); //獲取頂點v的在頂點陣列data中的下標 void Floyd(Graph& G); void showPath(const Graph& G, int u, int v); //展示最短路徑 }; #endif // GRAPH_H

  自己在嘗試寫程式碼的時候,要弄清除一個圖有哪些元素、一個演算法需具備哪些元素,才有思路、好下手寫程式碼喔~

Graph.cpp檔案程式碼

#include "Graph.h"
#include <iostream>
using namespace std;

Graph::Graph()		//預設構造
{
    //ctor
}

Graph* Graph::instance = nullptr;	//固定套路
Graph* Graph::getInstance()		//同上,記住就好,也可以自己嘗試理解下
{
    if(!instance) instance = new Graph();
    return instance;
}

int Graph::getIndex(const Graph& G, char v)		//獲取頂點v在頂點陣列中的下標
{
    for(int i = 0; i < G.n; i++)
        if(G.data[i] == v) return i;
    return -1;	//沒找到就返回-1
}

void Graph::createGraph(Graph& G)
{
    cout << "please input the number of vertex and arc:";
    cin >> G.n >> G.m;
    G.data = new char[G.n];		//動態建立一維陣列
    cout << "please input the value of vertice:";
    for(int p = 0; p < G.n; p++)
        cin >> G.data[p];
    char v1, v2;
    int power, i, j;
    G.w = new int*[G.n];	//動態建立二維陣列,申請了 int* 型別的G.n行空間
    for(int s = 0; s < G.n; s++)
        G.w[s] = new int[G.n];		//每一行申請一個int型別的G.n列空間

    for(int x = 0; x < G.n; x++)
        for(int y = 0; y < G.n; y++){
            if(x == y) G.w[x][y] = 0;	//邊的鄰接矩陣中左對角線權重(即自己的權重)都設為0,因為是多源的
            else G.w[x][y] = X;		//其他邊的權重初始化為無窮大
        }

    cout << "please input the weight of arc between 2 vertice as 100 A B:" << endl;
    for(int k = 0; k < G.m; k++){
        cin >> power >> v1 >> v2;
        i = getIndex(G, v1);
        j = getIndex(G, v2);
        if(i == -1 || j == -1){	//沒在頂點陣列中找到對應的頂點下標
                cout << "Sorry, I can't find the vertex" << endl;
                exit(-1);	//直接退出程式
        }
        G.w[i][j] = power;	//有向圖賦值邊的權重
    }
}

void Graph::Floyd(Graph& G)
{
    G.path = new int*[G.n];		//動態建立二維陣列
    for(int s = 0; s < G.n; s++){
        G.path[s] = new int[G.n];
        for(int t = 0; t < G.n; t++)
            G.path[s][t] = -1;	//初始化path鄰接矩陣的值
    }
    //特別注意:不能用fill函式來初始化動態二維陣列,因為動態new出來的空間不一定連續


    for(int v = 0; v < G.n; ++v)    //v是指在某兩個點中,它們之間點的下標
        for(int i = 0; i < G.n; ++i)
            for(int j = 0; j < G.n; ++j)
                if(G.w[i][j] > G.w[i][v] + G.w[v][j])	//看配合B站視訊講解效果更棒,這裡不多做解釋!
                {
                    G.w[i][j] = G.w[i][v] + G.w[v][j];
                    G.path[i][j] = v;
                }
}

void Graph::showPath(const Graph& G, int u, int v)
{	//看配合B站視訊講解效果更棒,該函式不多做解釋!

    if(G.path[u][v] == -1) cout << G.data[u] << " to " << G.data[v] << endl;	//B站輸出的是頂點序號,我這輸出的是頂點的值
    else{
        int mid = G.path[u][v];
        showPath(G, u, mid);
        showPath(G, mid, v);
    }
}

Graph::~Graph()		//虛解構函式作用:一般都是用來程式結束後釋放new出來的記憶體
{
    delete[] data;

    for(int i = 0; i < n; i++)
        delete[] w[i];
    delete[] w;

    for(int i = 0; i < n; i++)
        delete[] path[i];
    delete[] path;
}

  其實我們在寫演算法的時候,無非就是對資料的儲存進行操作(對二維陣列的操作),這也是演算法的本質。

main.cpp檔案程式碼

#include <iostream>
#include "Graph.h"	//自己寫的標頭檔案要用引號

using namespace std;

int main()
{
    char v1, v2;
    int a, b;
    Graph G;
    Graph::getInstance()->createGraph(G);	//用例項來調取抽象類的函式方法
    Graph::getInstance()->Floyd(G);
    cout << "please input which two vertice you want to show the shortest path between them:";
    cin >> v1 >> v2;
    a = Graph::getInstance()->getIndex(G, v1);
    b = Graph::getInstance()->getIndex(G, v2);
    Graph::getInstance()->showPath(G, a, b);
    return 0;
}

例子展示

Input(點我可進入連結