单源最短路径—Dijkstra算法(C++)

最近复习图算法,练练手
先拿Dijkstra算法开刀吧

以下是C++代码

包含:Dijkstra算法函数(返回源节点到其余节点之间的最短路径)、路径打印输出函数

PS:本人只喜欢用vector,不喜欢用原生数组;只喜欢string,不喜欢char*、char[]什么乱七八糟的。

#include 
#include 

using namespace std;

typedef int DATA_TYPE;  // 权值为int型
const DATA_TYPE NO_EDGE = 10000000;  // 表示没有该边

// 图的结构体定义
struct MatrixGraph
{
    vector<vector > weights;
    int vertexNum;  // 其实定义了邻接矩阵,这个也可以省
};

// 路径格式转换(从点对链接式转换到序列式)
vector<int> getVisitPath(vector<int> path, int startNode, int endNode)
{
    vector<int> visitPath;
    visitPath.push_back(endNode);

    if (path[endNode] != -1)
    {
        while (path[endNode] != startNode)
        {
            visitPath.insert(visitPath.begin(), path[endNode]);
            endNode = path[endNode];
        }
    }

    visitPath.insert(visitPath.begin(), startNode);
    return visitPath;
}

// 输出各条最短路径
void displayPath(vector distance, vector<int> path, int startNode)
{
    for (size_t i = 0; i < path.size(); ++i)
    {
        // 排除自己和自己 以及 不可达的路径
        if (i != startNode && distance[i] < NO_EDGE)
        {
            vector<int> visitPath = getVisitPath(path, startNode, i);
            cout << "From " << visitPath[0] << " to " << visitPath[visitPath.size() - 1] << "||  ";
            cout << "Distance: " << distance[i] << "  ||  Path:  ";

            for (size_t j = 0; j < visitPath.size() - 1; ++j)
            {
                cout << visitPath[j] << "->";
            }
            cout << visitPath[visitPath.size() - 1] << endl;
        }

    }
}

// Dijkstra算法
vector dijkstra(vector<vector > weights, int startNode)
{
    vector distance;  // 从源节点到其余各个节点的最短路径数组
    vector<int> path;  // 访问路径(点对)
    vector<int> S;  // 已访问的
    DATA_TYPE minDistance;  // 单次循环的最小值

    int vertexNum = weights.size();

    for (size_t i = 0; i < vertexNum; ++i)
    {
        // 最短路径初始化
        distance.push_back(weights[startNode][i]);
        // 已访问标记数组初始化
        S.push_back(0);  // 0表示未访问

        // 路径初始化
        if (weights[startNode][i] != NO_EDGE)
            path.push_back(startNode);  // 可达
        else
            path.push_back(-1);  // 不可达记为-1
    }

    S[startNode] = 1;  // 源节点放入S中
    path[startNode] = startNode;  // 路径开始为startNode 该值可随意

    size_t k;  // 最近顶点

    for (size_t i = 0; i < vertexNum; ++i)
    {
        minDistance = NO_EDGE;
        for (size_t j = 0; j < vertexNum; ++j)
        {
            if ((S[j] == 0) && (distance[j] < minDistance))
            {
                k = j;
                minDistance = distance[j];
            }
        }
        S[k] = 1;  // 最小 则将顶点k加入S

        for (size_t j = 0; j < vertexNum; ++j)
        {
            if (S[j] == 0)
            {
                // 对于所有与k相邻的节点(即可从k到达这些节点)
                if ((weights[k][j] < NO_EDGE) && (distance[k] + weights[k][j] < distance[j]))
                {
                    // 若新路径的长度小于最初判断时的长度,则更新
                    distance[j] = distance[k] + weights[k][j];
                    path[j] = k;  // 添加k到路径中
                }
            }
        }
    }

    // 输出路径情况
    displayPath(distance, path, startNode);

    return distance;
}


int main() {

    // 图的初始化
    // 顶点编号必须为从0开始的连续的整数(若不是,先转换)
    // 图为有向图
    MatrixGraph graph;
    graph.vertexNum = 7;  // 定义了邻接矩阵 这个可以省
    graph.weights.push_back(vector{0, 4, 6, 6, NO_EDGE, NO_EDGE, NO_EDGE});
    graph.weights.push_back(vector{NO_EDGE, 0, 1, NO_EDGE, 7, NO_EDGE, NO_EDGE});
    graph.weights.push_back(vector{NO_EDGE, NO_EDGE, 0, NO_EDGE, 6, 4, NO_EDGE});
    graph.weights.push_back(vector{NO_EDGE, NO_EDGE, 2, 0, NO_EDGE, 5, NO_EDGE});
    graph.weights.push_back(vector{NO_EDGE, NO_EDGE, NO_EDGE, NO_EDGE, 0, NO_EDGE, 6});
    graph.weights.push_back(vector{NO_EDGE, NO_EDGE, NO_EDGE, NO_EDGE, 1, 0, 8});
    graph.weights.push_back(vector{NO_EDGE, NO_EDGE, NO_EDGE, NO_EDGE, NO_EDGE, NO_EDGE, 0});

    vector distance = dijkstra(graph.weights, 1);

    return 0;
}

测试用例图如下:

编译环境(CLion 2016 with MinGW G++, GDB 7.11)

输出结果:
From 1 to 2|| Distance: 1 || Path: 1->2
FFrom 1 to 4|| Distance: 6 || Path: 1->2->5->4
From 1 to 5|| Distance: 5 || Path: 1->2->5
From 1 to 6|| Distance: 12 || Path: 1->2->5->4->6

你可能感兴趣的:(算法)