最短路径算法设计与实现(Dijkstra算法和Floyd算法)

1.问题描述和需求分析

随着计算机、网络、Android的兴起与发展,人们在出行时越来越离不开计算机的帮助。人们在旅行时越来越需要地图的帮助。在人们查找最佳行程路线时,便涉及了最短路径问题。用户想从A地到B地,如何查找最短路径,最快到达;以及如何在一组地点中找到相互间的最短路径。这其实便是最短路径算法解决的问题。
本文便是围绕最短路径问题,设计并实现Dijstra和Floyd算法。

2. 算法介绍

2.1 Dijkstra算法

Dijkstra算法又称为单源最短路径,所谓单源是在一个有向图中,从一个顶点出发,求该顶点至所有可到达顶点的最短路径问题。

1) 算法思想
设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。

2)算法步骤
①初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则

2.2 Floyd算法

Floyd算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。

1)算法思想
Floyd算法是典型的动态规划算法,其思想如下:
从任意节点i到任意节点j的最短路径仅仅只有2种可能,1是直接从i到j,2是从i经过若干个节点k到j。所以,假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。
2).算法步骤
①从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。
②对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是,更新它。

3.程序设计

3.1 图的数据结构

为了方便存储图的顶点信息和路径权值, 图的权值采用邻接矩阵的形式来存储。

设计数据结构如下:

typedef struct _Graph
{
    int     arrArcs[MAX_VERTEX_COUNT][MAX_VERTEX_COUNT];    // 邻接矩阵
    int     nVertexCount;                               // 顶点数量
    int     nArcCount;                                  // 边的数量
} Graph;

3.2 图的数据录入函数

为了方便录入,设计两种录入方式,一种为手动邻接矩阵值信息,一种是设定最大权值,自动生成随机数来生成邻接矩阵。

数据录入模块封装为一个函数,其实现如下:

/************************************************************************/
/* 图数据录入算法:根据命令行提示将邻接矩阵存储到图Graph中
          录入方式有两种,自动生成和手动录入
*/
/*     
参数:
    Graph *pGraph       图数据结构
*/
/************************************************************************/

void StoreGraphData( Graph *pGraph )
{
    cout << "算法采用邻接矩阵来存储图的相关数据,因此请按指示输入数据" << endl;
    cout << "请输入顶点数量(最多50个顶点): ";
    cin >> pGraph->nVertexCount;
    cout << "请输入边的数量: ";
    cin >> pGraph->nArcCount;
    cout << endl << "自动生成邻接矩阵请输入1,手动输入邻接矩阵请输入0:" ;
    int nWay = 1;
    cin >> nWay;
    if ( 1 == nWay) // 自动生成
    {
        cout << endl << "请输入随机数范围的最大值:" ;
        int number;
        cin >> number;
        srand( (unsigned) time(NULL) ); //用时间做种,每次产生随机数不一样
        for ( int row = 0; row < pGraph->nVertexCount; ++row )
        {
            for ( int col = 0; col < pGraph->nVertexCount; ++col )
            {
                if (row == col)
                    pGraph->arrArcs[row][col] = 0;
                else 
                    pGraph->arrArcs[row][col] = rand() % ( number + 10 ); //产生0 - (number+10)的随机数

                // 如果输入数据大于number,那么视作距离为无穷远,用MAX_DISTANCE代表
                if (pGraph->arrArcs[row][col] >= number )  
                    pGraph->arrArcs[row][col] = MAX_DISTANCE;
            }
        }
    } 
    else
    {
        cout << endl << "请输入邻接矩阵数据(非负数,按行输入,大于9999的数代表无穷远):" << endl;
        for ( int row = 0; row < pGraph->nVertexCount; ++row )
        {
            for ( int col = 0; col < pGraph->nVertexCount; ++col )
            {
                cin >> pGraph->arrArcs[row][col];

                // 如果输入数据大于9999,那么距离为无穷远,用MAX_DISTANCE代表
                if (pGraph->arrArcs[row][col] > 9999) 
                    pGraph->arrArcs[row][col] = MAX_DISTANCE;
            }
        }
    }
    cout << endl << "/////////////////////////////邻接矩阵/////////////////////////////////////" << endl;
    for ( int row = 0; row < pGraph->nVertexCount; ++row )
    {
        for ( int col = 0; col < pGraph->nVertexCount; ++col )
        {
            if ( pGraph->arrArcs[row][col] == MAX_DISTANCE)
                cout << "   OC ";
            else
                printf("%5d ",  pGraph->arrArcs[row][col]);
        }
        cout << endl;
    }
    cout << endl;
    cout << "//////////////////////////////////////////////////////////////////////////" << endl << endl;
}

3.3 Dijkstra算法

/************************************************************************/
/* Dijkstra算法:求出从i到任意节点的最短路径
*/
/*     
参数:
    int arrArcs[][MAX_VERTEX_COUNT],          有向图邻接矩阵
    const int nVertexCount,                   节点数目
    const int startVertex,                    源节点
    int *pDistance,                            各个节点到达源节点的距离
    int *pPreVertex                           各个节点的前一个节点
*/
/************************************************************************/


void Dijkstra(int arrArcs[][MAX_VERTEX_COUNT], const int nVertexCount,  const int startVertex, int *pDistance, int *pPreVertex)
{
    // isIns用于判断所有的节点是否在S集合中,初始为false,每进入一个设置对应为true,直到所有为true,算法停止
    vector isInS;                  //是否已经在S集合中(S中的点均已算出从i到其的最短路径)
    isInS.reserve(0);                    // 设置大小为0
    isInS.assign(nVertexCount, false);   //重新分配vector大小,所有的节点都不在S集合中

    int i, j;
    // Step 1: 先求出i,j之间不通过第三方节点转发的距离
    //         初始化pDistance和pPreVertex数组,此时可以求出i->j不通过其他点的距离
    for(j =0; j < nVertexCount; ++j)
    {
        // 第一次遍历时,查找的最短距离为两点之间不通过第三方的最短距离
        pDistance[j] = arrArcs[startVertex][j];
        if(arrArcs[startVertex][j] < MAX_DISTANCE)
            pPreVertex[j] = startVertex;  // i,j之间可以直连,那么j的前序节点便是i
        else
            pPreVertex[j] = -1;       // -1表示前一节点未知
    }
    pPreVertex[startVertex] = -1;     // 开始节点的前序节点未知

    // Step 2: 求出i,j之间通过第三方节点k转发的最短距离
    /*开始使用贪心思想循环处理不在S集合中的每一个节点*/
    isInS[startVertex] = true;          //开始节点放入S集合中
    int k = startVertex;                // 标记中间节点

    //开始节点已经存放在S中了,还有nVertexCount-1个节点要处理,故i从1开始
    for (i = 1; i < nVertexCount; i ++)  
    {

        // Step 2.1 : 寻找不在S集合中的距离i的distance最小的节点(依次遍历距离矩阵)
        int nextVertex = k;
        int tempDistance = MAX_DISTANCE;
        for(j = 0; j < nVertexCount; ++j)
        {
            //寻找不在S集合中的距离i的distance最小的节点
            if((isInS[j] == false) && (pDistance[j] < tempDistance))
            {
                nextVertex = j;
                tempDistance = pDistance[j];
            }
        }
        // 标记:一轮循环后,可以求得在当前S下,距离i的最近的不在S中的点,并保存数据
        isInS[nextVertex] = true; //距离i最近的节点nextVertex放入S集合中
        k = nextVertex;           //下一次寻找的开始节点k

        // Step 2.2 : 在S加入新节点后,计算从i到j的最短距离,更新distance:
        //            以k为新考虑的中间点,计算从i通过k转发到达j的距离,并与原有的从i直接到j的距离进行比较,选取最小值
        for (j =0; j < nVertexCount; j ++)
        {
            // 仅需计算不在S中的节点(从i出发到达S中的节点的距离是最短的)
            if (isInS[j] == false && arrArcs[k][j] < MAX_DISTANCE)  
            {
                if (pDistance[ k ] + arrArcs[ k ][ j ] < pDistance[ j ]) //以k为新考虑的中间点,计算从i通过k转发到达j的距离
                {
                    pDistance[ j ] = pDistance[ k ] + arrArcs[ k ][ j ];
                    pPreVertex[ j ] = k;
                }
            }
        }
    }
}

3.4 Floyd 算法

/************************************************************************/
/* Floyd 算法:求出所有节点两两之间的最短路径
*/
/*     
参数:
    Graph * pGraph,                       图的数据结构
    int arrDistance[][MAX_VERTEX_COUNT],  最短距离
    int arrPath[][MAX_VERTEX_COUNT],      最短路径索引
    int nVertexCount                      节点数目
*/
/************************************************************************/
void Floyd(Graph * pGraph, int arrDistance[][MAX_VERTEX_COUNT], int arrPath[][MAX_VERTEX_COUNT])
{
    int i, j, k;
    int nVertexCount = pGraph->nVertexCount;
    // Step 1:初始化arrDistance矩阵和arrPath矩阵
    //     第一次循环时,设置i,j之间的距离即为两者之间直线距离; 
    //     从i出发的到达j的任一节点的前序节点都是i
    for ( i = 0; i < nVertexCount; ++i )
    {
        for ( j = 0; j < nVertexCount; ++j )
        {
            arrDistance[i][j] = pGraph->arrArcs[i][j];
            arrPath[i][j] = i;
        }
    }
    // Step 2:动态规划
    // Dis(i,j)为节点i到节点j的最短路径的距离,
    //      对于每一个节点k,检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,
    //      如果成立,证明从i到k再到j的路径比i直接到j的路径短,便设置Dis(i,j) = Dis(i,k) + Dis(k,j)
    //      当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离

    for ( k = 0; k < nVertexCount; ++k )
    {
        for ( i = 0; i < nVertexCount; ++i )
        {
            for ( j = 0; j < nVertexCount; ++j )
            {
                // 对于每一个节点k,检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,
                if ( arrDistance[i][k] + arrDistance[k][j] < arrDistance[i][j] )
                {
                    // 找到更短路径
                    arrDistance[i][j] = arrDistance[i][k] + arrDistance[k][j];
                    // 存储路径索引值
                    arrPath[i][j] = arrPath[k][j];
                }
            }
        }
    }
}

3.5 最短路径输出模块

为了方便输出实验结果,设计了两个输出函数:

1) Dijkstra算法输出函数

/************************************************************************/
/* Dijkstra 算法结果输出函数:输出Floyd算法的最短路径
*/
/*     
参数:
    int *pDistance,                           各个节点到达源节点的距离
    int *pPreVertex                           各个节点的前一个节点
    int nVertexCount,                         顶点数目
    int startVertex,                          源节点
*/
/************************************************************************/
void DijkstraPrintResult(int *pDistance, int *pPreVertex, int nVertexCount, int startVertex)
{
    int i, j;
    i = startVertex;
    for(j =0; j < nVertexCount; ++j)
    {
        if (j!=i) // 节点不为自身
        {
            printf("%2d -> %2d \t\t", i, j); 
            if ( pDistance[j] == MAX_DISTANCE)
                cout << "OC\t\t";
            else
                cout << pDistance[j] << "\t\t";

            int index = j;
            stack<int > trace;
            // 逆向查找最短路径,并放置到stack
            while (pPreVertex[index] != -1) {
                trace.push(pPreVertex[index]);
                index = pPreVertex[index];
            }

            // 退栈,即可得到正确的路径
            if (!trace.empty()) //非空
            {
                while (!trace.empty()) {
                    cout << trace.top() << " -> ";
                    trace.pop();
                } 
            } 
            else
            {
                cout  << i << " -> ";
            }
            cout << j << endl;
        }  
    }
}

2)Floyd算法输出函数

/************************************************************************/
/* Floyd 算法结果输出函数:输出Floyd算法的最短路径
*/
/*     
参数:
    int arrDistance[][MAX_VERTEX_COUNT],     最短路径距离
    int arrPath[][MAX_VERTEX_COUNT],         最短路径节点索引
    int nVertexCount                         顶点数目
*/
/************************************************************************/
void FloydPrintResult( int arrDistance[][MAX_VERTEX_COUNT], int arrPath[][MAX_VERTEX_COUNT], int nVertexCount )
{
    cout << "源点 -> 目的点\t\t距离 \t\t 路径" << endl;

    for ( int i = 0; i < nVertexCount; ++i )
    {
        for ( int j = 0; j < nVertexCount; ++j )
        {
            if ( i != j )   // 节点不是自身
            {
                printf("%2d -> %2d \t\t", i, j); 
                if ( arrDistance[i][j] == MAX_DISTANCE)
                    cout << "OC\t\t";
                else
                    cout << arrDistance[i][j] << "\t\t";

                int index = j;
                stack<int > trace;
                // 逆向查找最短路径,并放置到stack
                do 
                {
                    index = arrPath[i][index];
                    trace.push( index );
                } while ( index != i );

                // 退栈,即可得到正确的路径
                while (!trace.empty()) {
                    cout << trace.top() << " -> ";
                    trace.pop();
                } 
                cout << j << endl;
            }
        }
    }
}

4.完整的实现代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using std::cout;
using std::endl;
using std::cin;
using std::vector;
using std::stack;

#define MAX_DISTANCE 9999           // 最大值
#define MAX_VERTEX_COUNT 50// 最大顶点个数
//////////////////////////////////////////////////////////////////////////

typedef struct _Graph
{
    int     arrArcs[MAX_VERTEX_COUNT][MAX_VERTEX_COUNT];    // 邻接矩阵
    int     nVertexCount;                               // 顶点数量
    int     nArcCount;                                  // 边的数量
} Graph;
//////////////////////////////////////////////////////////////////////////

/************************************************************************/
/* 图数据录入算法:根据命令行提示将邻接矩阵存储到图Graph中
          录入方式有两种,自动生成和手动录入
*/
/*     
参数:
    Graph *pGraph       图数据结构
*/
/************************************************************************/

void StoreGraphData( Graph *pGraph )
{
    cout << "算法采用邻接矩阵来存储图的相关数据,因此请按指示输入数据" << endl;
    cout << "请输入顶点数量(最多50个顶点): ";
    cin >> pGraph->nVertexCount;
    cout << "请输入边的数量: ";
    cin >> pGraph->nArcCount;
    cout << endl << "自动生成邻接矩阵请输入1,手动输入邻接矩阵请输入0:" ;
    int nWay = 1;
    cin >> nWay;
    if ( 1 == nWay) // 自动生成
    {
        cout << endl << "请输入随机数范围的最大值:" ;
        int number;
        cin >> number;
        srand( (unsigned) time(NULL) ); //用时间做种,每次产生随机数不一样
        for ( int row = 0; row < pGraph->nVertexCount; ++row )
        {
            for ( int col = 0; col < pGraph->nVertexCount; ++col )
            {
                if (row == col)
                    pGraph->arrArcs[row][col] = 0;
                else 
                    pGraph->arrArcs[row][col] = rand() % ( number + 10 ); //产生0 - (number+10)的随机数

                // 如果输入数据大于number,那么视作距离为无穷远,用MAX_DISTANCE代表
                if (pGraph->arrArcs[row][col] >= number )  
                    pGraph->arrArcs[row][col] = MAX_DISTANCE;
            }
        }
    } 
    else
    {
        cout << endl << "请输入邻接矩阵数据(非负数,按行输入,大于9999的数代表无穷远):" << endl;
        for ( int row = 0; row < pGraph->nVertexCount; ++row )
        {
            for ( int col = 0; col < pGraph->nVertexCount; ++col )
            {
                cin >> pGraph->arrArcs[row][col];

                // 如果输入数据大于9999,那么距离为无穷远,用MAX_DISTANCE代表
                if (pGraph->arrArcs[row][col] > 9999) 
                    pGraph->arrArcs[row][col] = MAX_DISTANCE;
            }
        }
    }
    cout << endl << "/////////////////////////////邻接矩阵/////////////////////////////////////" << endl;
    for ( int row = 0; row < pGraph->nVertexCount; ++row )
    {
        for ( int col = 0; col < pGraph->nVertexCount; ++col )
        {
            if ( pGraph->arrArcs[row][col] == MAX_DISTANCE)
                cout << "   OC ";
            else
                printf("%5d ",  pGraph->arrArcs[row][col]);
        }
        cout << endl;
    }
    cout << endl;
    cout << "//////////////////////////////////////////////////////////////////////////" << endl << endl;
}

/************************************************************************/
/* Dijkstra算法:求出从i到任意节点的最短路径
*/
/*     
参数:
    int arrArcs[][MAX_VERTEX_COUNT],          有向图邻接矩阵
    const int nVertexCount,                   节点数目
    const int startVertex,                    源节点
    int *pDistance,                            各个节点到达源节点的距离
    int *pPreVertex                           各个节点的前一个节点
*/
/************************************************************************/


void Dijkstra(int arrArcs[][MAX_VERTEX_COUNT], const int nVertexCount,  const int startVertex, int *pDistance, int *pPreVertex)
{
    // isIns用于判断所有的节点是否在S集合中,初始为false,每进入一个设置对应为true,直到所有为true,算法停止
    vector<bool> isInS;                  //是否已经在S集合中(S中的点均已算出从i到其的最短路径)
    isInS.reserve(0);                    // 设置大小为0
    isInS.assign(nVertexCount, false);   //重新分配vector大小,所有的节点都不在S集合中

    int i, j;
    // Step 1: 先求出i,j之间不通过第三方节点转发的距离
    //         初始化pDistance和pPreVertex数组,此时可以求出i->j不通过其他点的距离
    for(j =0; j < nVertexCount; ++j)
    {
        // 第一次遍历时,查找的最短距离为两点之间不通过第三方的最短距离
        pDistance[j] = arrArcs[startVertex][j];
        if(arrArcs[startVertex][j] < MAX_DISTANCE)
            pPreVertex[j] = startVertex;  // i,j之间可以直连,那么j的前序节点便是i
        else
            pPreVertex[j] = -1;       // -1表示前一节点未知
    }
    pPreVertex[startVertex] = -1;     // 开始节点的前序节点未知

    // Step 2: 求出i,j之间通过第三方节点k转发的最短距离
    /*开始使用贪心思想循环处理不在S集合中的每一个节点*/
    isInS[startVertex] = true;          //开始节点放入S集合中
    int k = startVertex;                // 标记中间节点

    //开始节点已经存放在S中了,还有nVertexCount-1个节点要处理,故i从1开始
    for (i = 1; i < nVertexCount; i ++)  
    {

        // Step 2.1 : 寻找不在S集合中的距离i的distance最小的节点(依次遍历距离矩阵)
        int nextVertex = k;
        int tempDistance = MAX_DISTANCE;
        for(j = 0; j < nVertexCount; ++j)
        {
            //寻找不在S集合中的距离i的distance最小的节点
            if((isInS[j] == false) && (pDistance[j] < tempDistance))
            {
                nextVertex = j;
                tempDistance = pDistance[j];
            }
        }
        // 标记:一轮循环后,可以求得在当前S下,距离i的最近的不在S中的点,并保存数据
        isInS[nextVertex] = true; //距离i最近的节点nextVertex放入S集合中
        k = nextVertex;           //下一次寻找的开始节点k

        // Step 2.2 : 在S加入新节点后,计算从i到j的最短距离,更新distance:
        //            以k为新考虑的中间点,计算从i通过k转发到达j的距离,并与原有的从i直接到j的距离进行比较,选取最小值
        for (j =0; j < nVertexCount; j ++)
        {
            // 仅需计算不在S中的节点(从i出发到达S中的节点的距离是最短的)
            if (isInS[j] == false && arrArcs[k][j] < MAX_DISTANCE)  
            {
                if (pDistance[ k ] + arrArcs[ k ][ j ] < pDistance[ j ]) //以k为新考虑的中间点,计算从i通过k转发到达j的距离
                {
                    pDistance[ j ] = pDistance[ k ] + arrArcs[ k ][ j ];
                    pPreVertex[ j ] = k;
                }
            }
        }
    }
}

/************************************************************************/
/* Floyd 算法:求出所有节点两两之间的最短路径
*/
/*     
参数:
    Graph * pGraph,                       图的数据结构
    int arrDistance[][MAX_VERTEX_COUNT],  最短距离
    int arrPath[][MAX_VERTEX_COUNT],      最短路径索引
    int nVertexCount                      节点数目
*/
/************************************************************************/
void Floyd(Graph * pGraph, int arrDistance[][MAX_VERTEX_COUNT], int arrPath[][MAX_VERTEX_COUNT])
{
    int i, j, k;
    int nVertexCount = pGraph->nVertexCount;
    // Step 1:初始化arrDistance矩阵和arrPath矩阵
    //     第一次循环时,设置i,j之间的距离即为两者之间直线距离; 
    //     从i出发的到达j的任一节点的前序节点都是i
    for ( i = 0; i < nVertexCount; ++i )
    {
        for ( j = 0; j < nVertexCount; ++j )
        {
            arrDistance[i][j] = pGraph->arrArcs[i][j];
            arrPath[i][j] = i;
        }
    }
    // Step 2:动态规划
    // Dis(i,j)为节点i到节点j的最短路径的距离,
    //      对于每一个节点k,检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,
    //      如果成立,证明从i到k再到j的路径比i直接到j的路径短,便设置Dis(i,j) = Dis(i,k) + Dis(k,j)
    //      当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离

    for ( k = 0; k < nVertexCount; ++k )
    {
        for ( i = 0; i < nVertexCount; ++i )
        {
            for ( j = 0; j < nVertexCount; ++j )
            {
                // 对于每一个节点k,检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,
                if ( arrDistance[i][k] + arrDistance[k][j] < arrDistance[i][j] )
                {
                    // 找到更短路径
                    arrDistance[i][j] = arrDistance[i][k] + arrDistance[k][j];
                    // 存储路径索引值
                    arrPath[i][j] = arrPath[k][j];
                }
            }
        }
    }
}

/************************************************************************/
/* Dijkstra 算法结果输出函数:输出Floyd算法的最短路径
*/
/*     
参数:
    int *pDistance,                           各个节点到达源节点的距离
    int *pPreVertex                           各个节点的前一个节点
    int nVertexCount,                         顶点数目
    int startVertex,                          源节点
*/
/************************************************************************/
void DijkstraPrintResult(int *pDistance, int *pPreVertex, int nVertexCount, int startVertex)
{
    int i, j;
    i = startVertex;
    for(j =0; j < nVertexCount; ++j)
    {
        if (j!=i) // 节点不为自身
        {
            printf("%2d -> %2d \t\t", i, j); 
            if ( pDistance[j] == MAX_DISTANCE)
                cout << "OC\t\t";
            else
                cout << pDistance[j] << "\t\t";

            int index = j;
            stack<int > trace;
            // 逆向查找最短路径,并放置到stack
            while (pPreVertex[index] != -1) {
                trace.push(pPreVertex[index]);
                index = pPreVertex[index];
            }

            // 退栈,即可得到正确的路径
            if (!trace.empty()) //非空
            {
                while (!trace.empty()) {
                    cout << trace.top() << " -> ";
                    trace.pop();
                } 
            } 
            else
            {
                cout  << i << " -> ";
            }
            cout << j << endl;
        }  
    }
}


/************************************************************************/
/* Floyd 算法结果输出函数:输出Floyd算法的最短路径
*/
/*     
参数:
    int arrDistance[][MAX_VERTEX_COUNT],     最短路径距离
    int arrPath[][MAX_VERTEX_COUNT],         最短路径节点索引
    int nVertexCount                         顶点数目
*/
/************************************************************************/
void FloydPrintResult( int arrDistance[][MAX_VERTEX_COUNT], int arrPath[][MAX_VERTEX_COUNT], int nVertexCount )
{
    cout << "源点 -> 目的点\t\t距离 \t\t 路径" << endl;

    for ( int i = 0; i < nVertexCount; ++i )
    {
        for ( int j = 0; j < nVertexCount; ++j )
        {
            if ( i != j )   // 节点不是自身
            {
                printf("%2d -> %2d \t\t", i, j); 
                if ( arrDistance[i][j] == MAX_DISTANCE)
                    cout << "OC\t\t";
                else
                    cout << arrDistance[i][j] << "\t\t";

                int index = j;
                stack<int > trace;
                // 逆向查找最短路径,并放置到stack
                do 
                {
                    index = arrPath[i][index];
                    trace.push( index );
                } while ( index != i );

                // 退栈,即可得到正确的路径
                while (!trace.empty()) {
                    cout << trace.top() << " -> ";
                    trace.pop();
                } 
                cout << j << endl;
            }
        }
    }
}

int main()
{
    Graph graph;
    // 存储数据到Graph结构
    StoreGraphData( &graph );

    /////////////////////////////Dijkstra/////////////////////////////////////
    cout << "/////////////////////////////Dijkstra/////////////////////////////////////" << endl;
    int * pDistance = new int [graph.nVertexCount]; // 存储从i到j的最短距离
    int * pPreVertex = new int [graph.nVertexCount]; // 存储从i到j的最短路径

    cout << "源点 -> 目的点\t\t距离 \t\t 路径" << endl;

    for (int i =0 ; i < graph.nVertexCount; ++i )
    {
        Dijkstra(graph.arrArcs, graph.nVertexCount, i, pDistance, pPreVertex);
        DijkstraPrintResult(pDistance, pPreVertex, graph.nVertexCount, i);
    }

    delete [] pDistance;
    delete [] pPreVertex;
    cout << "//////////////////////////////////////////////////////////////////////////" << endl << endl;
    //////////////////////////////////////////////////////////////////////////

    /////////////////////////////Floyd////////////////////////////////////////
    cout << "/////////////////////////////Floyd////////////////////////////////////////" << endl;

    int nArrDis[MAX_VERTEX_COUNT][MAX_VERTEX_COUNT];
    int nArrPath[MAX_VERTEX_COUNT][MAX_VERTEX_COUNT];

    Floyd(&graph, nArrDis, nArrPath);

    FloydPrintResult( nArrDis, nArrPath, graph.nVertexCount );
    cout << "//////////////////////////////////////////////////////////////////////////" << endl;
    //////////////////////////////////////////////////////////////////////////

    system("pause");
    return 0;
}

你可能感兴趣的:(Algorithems)