• 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();
    }

  • 相关阅读:
    Docker容器进入的4种方式
    Linux启动/停止/重启Mysql数据库的方法
    MySQL replace函数替换字符串语句的用法(mysql字符串替换)
    php从数组中随机筛选出指定个数的值
    Beyond Compare 4 30天试用期后,破解方法
    MYSQL:1213 Deadlock问题排查历程
    uniapp 屏幕高度
    如何系统学习Spring框架
    mysql 批量修改表前缀
    DHCP中继配置案例
  • 原文地址:https://www.cnblogs.com/wangtianning1223/p/16347173.html
Copyright © 2020-2023  润新知