1. 程式人生 > 其它 >dijsktra求最短路徑

dijsktra求最短路徑

講演算法原理的有很多,直接貼程式碼

dijkstra演算法是直接對鄰接矩陣進行操作求出最短路徑的,我專案中的圖結構需要轉化成鄰接矩陣,所以會有下面程式碼

圖結構是一個map,first表示節點的index,second是一個結構體,包含節點的詳細資訊

map<int, node> routeTable;
struct node
{
public:  
   string ip;                //節點的ip
   int port;                 //節點的埠
   vector<OP_TYPE> ops;       //節點支援的OP
   float
overload; //節點的負載 bool status; // 節點的狀態 int ncmIndex; //ncm index int reportCount; vector<pair<int,int>> adjacencyIndex; //鄰接點的index及距離 };

所以需要根據這個map來生成一個鄰接矩陣,dijkstra演算法是從圖的起點找出它與所有點的最短路徑,而我的需求是給定兩個點求他們在圖上的最短距離,所以生成鄰接矩陣不能按map本來的順序去生成,需要將輸入的兩個點作為鄰接矩陣的第一個點和最後一個點。舉例來說如果原來節點的順序是[0,1,2,3,4,5,6],我們想求2和4在圖上的最短距離,那麼就需要將map便利的順序變成[2,0,1,3,5,6,4]

生成鄰接矩陣

std::vector<std::vector<int>> GlobalRouteTable::getRouteAdjacentMatrix(
    int startNodeIndex, int endNodeIndex)
{
    std::vector<int> graphNodeOrder = {};
    // 將startNodeIndex和endNodeIndex對應的點作為圖遍歷的起點和重點
    // if(routeTable.find(startNodeIndex)==routeTable.end()||routeTable.find(endNodeIndex)==routeTable.end())
graphNodeOrder.push_back(startNodeIndex); for (auto it : routeTable) { if (it.first != startNodeIndex && it.first != endNodeIndex && it.second.adjacencyIndex[0].first != -1) graphNodeOrder.push_back(it.first); } graphNodeOrder.push_back(endNodeIndex); std::vector<std::vector<int>> adjacent_matrix; // 初始化鄰接矩陣 for (size_t i = 0; i < graphNodeOrder.size(); ++i) { std::vector<int> matrix_line = {}; for (size_t j = 0; j < graphNodeOrder.size(); ++j) matrix_line.push_back(65535); adjacent_matrix.push_back(matrix_line); } // 對角線0 for (size_t i = 0; i < graphNodeOrder.size(); ++i) adjacent_matrix[i][i] = 0; for (size_t i = 0; i < graphNodeOrder.size(); ++i) { for (auto j : routeTable[graphNodeOrder[i]].adjacencyIndex) { int tmp_index = 0; for (auto k = graphNodeOrder.begin(); k != graphNodeOrder.end(); ++k) { if (*k != j.first) tmp_index += 1; else break; } adjacent_matrix[i][tmp_index] = j.second; } } return adjacent_matrix; }

求最短路徑

int GlobalRouteTable::dijsktra(std::vector<std::vector<int>> &&graph_matrix)
{
    // init
    // 目標點到其他點的距離
    std::vector<int> dist = {};
    // 是否找到最短路徑
    std::vector<bool> target = {};
    // 初始化圖的第一個節點並錄入與之相鄰的節點的距離
    for (size_t i = 0; i < graph_matrix.size(); ++i) {
        dist.push_back(graph_matrix[0][i]);
        target.push_back(false);
    }
    target[0] = true;
    int min, k;
    // start search
    for (size_t i = 1; i < graph_matrix.size(); ++i) {
        min = 65535;
        for (size_t j = 1; j < graph_matrix.size(); ++j) {
            if (!target[j] && min > dist[j]) {
                min = dist[j];
                // 確定下一個要搜尋的點
                k = j;
            }
        }
        target[k] = true;
        for (size_t j = 1; j < graph_matrix.size(); ++j) {
            if (!target[j] && dist[j] > dist[k] + graph_matrix[k][j]) {
                dist[j] = dist[k] + graph_matrix[k][j];
            }
        }
    }
    return dist[dist.size() - 1];
}

函式呼叫

int GlobalRouteTable::getNodeDist(int startNodeIndex, int endNodeIndex)
{
    if (startNodeIndex == endNodeIndex) return 0;
    return dijsktra(std::move(getRouteAdjacentMatrix(startNodeIndex, endNodeIndex)));
}

圖結構

除了標記的變長是4,其餘的邊長都是1

 測試用例

#include "../../src/routeTable.h"

#include <gtest/gtest.h>

TEST(routetableTest, checkGetDist)
{
    auto ptr = GlobalRouteTable::GetInstance();
    std::cout << "load table result: " << ptr->loadRouteTable() << std::endl;
    //
    ASSERT_EQ(ptr->getNodeDist(0, 0), 0);
    ASSERT_EQ(ptr->getNodeDist(0, 1), 1);
    ASSERT_EQ(ptr->getNodeDist(0, 2), 1);
    ASSERT_EQ(ptr->getNodeDist(2, 1), 2);
    ASSERT_EQ(ptr->getNodeDist(2, 3), 1);
    ASSERT_EQ(ptr->getNodeDist(2, 6), 3);
    ASSERT_EQ(ptr->getNodeDist(0, 10), 4);
    ASSERT_EQ(ptr->getNodeDist(0, 11), 5);
    ASSERT_EQ(ptr->getNodeDist(1, 11), 6);
    ASSERT_EQ(ptr->getNodeDist(0, 12), 5);
    ASSERT_EQ(ptr->getNodeDist(0, 16), 6);
    ASSERT_EQ(ptr->getNodeDist(2, 12), 6);
    ASSERT_EQ(ptr->getNodeDist(2, 16), 7);
    ASSERT_EQ(ptr->getNodeDist(6, 16), 8);
}
int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}