最短路径算法C++实现(基于邻接矩阵有向图)

头文件:

 

/*****************************************************************************
 *                                    matrixallocate.h
 *
 * Allocate and delete two dimension array (matrix).
 *
 * Zhang Ming, 2010-01
 *****************************************************************************/


#ifndef MATRIXALLOCATE_H
#define MATRIXALLOCATE_H



namespace itlab
{

    /**
     * Allocate matrix by specified rows and columns.
     */
    template<typename Type>
    inline void makeMatrix( Type **&m, int rows, int cols )
    {
        m = new Type*[rows];
        for( int i=0; i<rows; ++i )
            m[i] = new Type[cols];
    }


    /**
     * Delete the matrix with specified rows.
     */
    template<typename Type>
    inline void deleteMatrix( Type **&m, int rows )
    {
        for( int i=0; i<rows; ++i )
            delete []m[i];

        delete []m;
        m = 0;
    }

}


#endif
// MATRIXALLOCATE_H

 

 

/*****************************************************************************
 *                                    amgraph.h
 *
 * Adjacency Matrix Based Directed Graph.
 *
 * This is a C++ template class for undirected graph with an adjacency matrix
 * representation. It provedes the general operations for graph, such as
 * insertVertex, removeVertex, insertEdge, removeEdge, getVertexNumber,
 * getEdgeNumber, getData, getWeight, getNextDst, and so on.
 *
 * It also includes the  Dijkstra algorithm for Single-Source Shortest Path
 * and Floyd algorithm for All-Pairs Shortest Paths.
 *
 * When debugging, use #define BOUNDS_CHECK above your "#include amgraph.h"
 * line. When done debugging, comment out #define BOUNDS_CHECK for better
 * performance.
 *
 * Zhang Ming, 2010-07
 *****************************************************************************/


#ifndef AMGRAPH_H
#define AMGRAPH_H


#include <iostream>
#include <cstdlib>
#include <cassert>
#include <constants.h>
#include <matrixallocate.h>


using namespace std;


namespace itlab
{

    /**
     * adjacency matrix based graph
     */
    template<typename Object, typename Weight>
    class AMGraph
    {

    public:

        static const Weight MAXWEIGHT = Weight(32767);
        static const Weight MINWEIGHT = Weight(-32768);

        explicit AMGraph( int n=INITSIZE );
        ~AMGraph();

        int getVertexNumber() const;
        int getEdgeNumber() const;

        Object getData( int i ) const;
        int getIndex( const Object &x ) const;
        Weight getWeight( int row, int col ) const;
        Weight getWeight( const Object &x1, const Object &x2 ) const;

        int getNextDst( const Object &x ) const;
        int getNextDst( const Object &x1, const Object &x2 ) const;

        void insertVertex( const Object &x );
        void removeVertex( const Object &x );
        void insertEdge( const Object &x1, const Object &x2, Weight c );
        void removeEdge( const Object &x1, const Object &x2 );

        void dijkstra( int start, Weight *dist, int *path );
        void floyd( Weight **dist, int **path );

    private:

        int curSize;
        int maxSize;
        int edgeNum;
        Object *vertexArray;
        Weight **edgeMatrix;

    };


    #include "amgraph-impl.h"

}
// namespace itlab


#endif
// AMGRAPH_H

 

实现文件:

 

/*****************************************************************************
 *                               AMGraph-impl.h
 *
 * Implementation for AMGraph class.
 *
 * Zhang Ming, 2010-07
 *****************************************************************************/


/**
 * constructors and destructor
 */
template<typename Object, typename Weight>
AMGraph<Object,Weight>::AMGraph( int n )
{
    maxSize = n;
    curSize = 0;
    edgeNum = 0;

    vertexArray = new Object[maxSize];
    makeMatrix( edgeMatrix, maxSize, maxSize );
    if( vertexArray == NULL || edgeMatrix == NULL )
    {
        cerr << "Out of memory!";
        exit(1);
    }

    for( int i=0; i<maxSize; ++i )
        for( int j=0; j<maxSize; ++j )
            edgeMatrix[i][j] = MAXWEIGHT;
    for( int i=0; i<maxSize; ++i )
            edgeMatrix[i][i] = MINWEIGHT;
}

template<typename Object, typename Weight>
AMGraph<Object,Weight>::~AMGraph()
{
    delete []vertexArray;
    deleteMatrix( edgeMatrix, maxSize );
}


/**
 * Get the vertex number of the graph.
 */
template<typename Object, typename Weight>
inline int AMGraph<Object,Weight>::getVertexNumber() const
{
    return curSize;
}


/**
 * Get the edge number of the graph.
 */
template<typename Object, typename Weight>
inline int AMGraph<Object,Weight>::getEdgeNumber() const
{
    return edgeNum;
}


/**
 * Return the content of vertex "i".
 */
template<typename Object, typename Weight>
inline Object AMGraph<Object,Weight>::getData( int i ) const
{
#ifdef BOUNDS_CHECK
    assert( 0 <= i );
    assert( i < curSize );
#endif

    return vertexArray[i];
}


/**
 * Return the index of vertex "x", if there is no shuch vertex, return -1.
 */
template<typename Object, typename Weight>
inline int AMGraph<Object,Weight>::getIndex( const Object &x ) const
{
    for( int i=0; i<curSize; ++i )
        if( vertexArray[i] == x )
            return i;

    return -1;
}


/**
 * Return weight on the edge between vertex "x1" and "x2".
 */
template<typename Object, typename Weight>
Weight AMGraph<Object,Weight>::getWeight( int row, int col ) const
{
#ifdef BOUNDS_CHECK
    assert( 0 <= row );
    assert( row < curSize );
    assert( 0 <= col );
    assert( col < curSize );
#endif

    return edgeMatrix[row][col];
}

template<typename Object, typename Weight>
Weight AMGraph<Object,Weight>::getWeight( const Object &x1, const Object &x2 ) const
{
    int v1 = getIndex(x1),
        v2 = getIndex(x2);

    if( v1 == -1 )
    {
        cerr << "There is no vertex: " << x1 << endl;
        return Weight(0);
    }
    else if( v2 == -1 )
    {
        cerr << "There is no vertex: " << x2 << endl;
        return Weight(0);
    }
    else
        return edgeMatrix[v1][v2];
}


/**
 * Get the position of the next adjacency point of vertex "x",
 * if there is no next adjacendy vertex, return -1;
 */
template<typename Object, typename Weight>
int AMGraph<Object,Weight>::getNextDst( const Object &x ) const
{
    int i = getIndex(x);

    if( i == -1 )
    {
        cerr << "There is no vertex: " << x << endl;
        return -1;
    }
    else
    {
        for( int j=0; j<curSize; ++j )
            if( MINWEIGHT < edgeMatrix[i][j] && edgeMatrix[i][j] < MAXWEIGHT )
                return j;
        return -1;
    }
}

template<typename Object, typename Weight>
int AMGraph<Object,Weight>::getNextDst( const Object &x1, const Object &x2 ) const
{
    int v1 = getIndex(x1),
        v2 = getIndex(x2);

    if( v1 == -1 )
    {
        cerr << "There is no vertex: " << x1 << endl;
        return -1;
    }
    else if( v2 == -1 )
    {
        cerr << "There is no vertex: " << x2 << endl;
        return -1;
    }
    else
    {
        for( int col=v2+1; col<curSize; ++col )
            if( MINWEIGHT < edgeMatrix[v1][col] && edgeMatrix[v1][col] < MAXWEIGHT )
                return col;
        return -1;
    }
}


/**
 * Insert a new vertex "x". If the vertex array is full, output
 * the FULL warning.
 */
template<typename Object, typename Weight>
void AMGraph<Object,Weight>::insertVertex( const Object &x )
{
    if( curSize < maxSize )
        vertexArray[curSize++] = x;
    else
        cerr << "The vertex table is full!" << endl;
}


/**
 * Remove the vertex "x".
 */
template<typename Object, typename Weight>
void AMGraph<Object,Weight>::removeVertex( const Object &x )
{
    int v = getIndex(x);

    if( v == -1 )
        cerr << "There is no vertex: " << x << endl;
    else
    {
        vertexArray[v] = vertexArray[curSize-1];

        for( int i=0; i<curSize; ++i )
            if( MINWEIGHT < edgeMatrix[i][v] && edgeMatrix[i][v] < MAXWEIGHT )
                edgeNum--;
        for( int j=0; j<curSize; ++j )
            if( MINWEIGHT < edgeMatrix[v][j] && edgeMatrix[v][j] < MAXWEIGHT )
                edgeNum--;

        for( int j=0; j<curSize; ++j )
            edgeMatrix[v][j] = edgeMatrix[curSize-1][j];
        for( int i=0; i<curSize; ++i )
            edgeMatrix[i][v] = edgeMatrix[i][curSize-1];

        curSize--;
    }
}


/**
 * Insert an edge (x1,x2) with weight "c". If the edge already exist then
 * return false, else return true.
 */
template<typename Object, typename Weight>
void AMGraph<Object,Weight>::insertEdge( const Object &x1, const Object &x2, Weight c )
{
    int v1 = getIndex(x1),
        v2 = getIndex(x2);

    if( v1 == -1 )
        cerr << "There is no vertex: " << x1 << endl;
    else if( v2 == -1 )
        cerr << "There is no vertex: " << x2 << endl;
    else
        if( v1 != v2 )
        {
            edgeMatrix[v1][v2] = c;
            edgeNum++;
        }
}


/**
 * Remove the edge (x1,x2).
 */
template<typename Object, typename Weight>
void AMGraph<Object,Weight>::removeEdge( const Object &x1, const Object &x2 )
{
    int v1 = getIndex(x1),
        v2 = getIndex(x2);

    if( v1 == -1 )
        cerr << "There is no vertex: " << x1 << endl;
    else if( v2 == -1 )
        cerr << "There is no vertex: " << x2 << endl;
    else
        if( v1 != v2 )
        {
            if( edgeMatrix[v1][v2] == MAXWEIGHT )
            {
                cerr << "There is no such edge between " << x1 << " and " << x2 << endl;
                return;
            }
            else
            {
                edgeMatrix[v1][v2] = MAXWEIGHT;
                edgeNum--;
            }
        }
}


/**
 * Dijkstra algorithm for Single-Source Shortest Path
 */
template<typename Object, typename Weight>
void AMGraph<Object,Weight>::dijkstra( int start, Weight *dist, int *path )
{
#ifdef BOUNDS_CHECK
    assert( 0 <= start );
    assert( start < curSize );
#endif

    bool *visited = new bool[curSize];
    for( int i=0; i<curSize; ++i )
    {
        visited[i] = false;
        dist[i] = edgeMatrix[start][i];
        if( dist[i] < MAXWEIGHT )
            path[i] = start;
        else
            path[i] = -1;
    }

    visited[start] = true;
    dist[start] = 0;

    for( int i=1; i<curSize; ++i )
    {
        Weight minDIst = MAXWEIGHT;
        for( int j=0; j<curSize; ++j )
            if( !visited[j] && dist[j] < minDIst )
            {
                minDIst = dist[j];
                start = j;
            }

        visited[start] = true;
        for( int j=0; j<curSize; ++j )
            if( !visited[j] && dist[start]+edgeMatrix[start][j] < dist[j] )
            {
                dist[j] = dist[start]+edgeMatrix[start][j];
                path[j] = start;
            }
    }

    /* output the result...
    for( int i=0; i<verNum; ++i )
    {
        if( dist[i] < g.MAXWEIGHT )
        {
            cout << i << ":\t" << dist[i] << "\t" << i << " <-- ";
            for( int j=path[i]; j!=start; j=path[j] )
                cout << j << " <-- ";
            cout << start << endl;
        }
        else
            cout << i << ":\tMAX\tNo Path!" <<endl;
    }
    */
}


/**
 * Floyd algorithm for All-Pairs Shortest Path
 */
template<typename Object, typename Weight>
void AMGraph<Object,Weight>::floyd( Weight **dist, int **path )
{
    for( int i=0; i<curSize; ++i )
    {
        for( int j=0; j<curSize; ++j )
        {
            dist[i][j] = edgeMatrix[i][j];

            if( dist[i][j] < MAXWEIGHT )
                path[i][j] = i;
            else
                path[i][j] = -1;
        }
        dist[i][i] = Weight(0);
    }

    for( int v=0; v<curSize; ++v )
        for( int i=0; i<curSize; ++i )
            for( int j=0; j<curSize; ++j )
                if( dist[i][j] > dist[i][v]+dist[v][j] )
                {
                    dist[i][j] = dist[i][v]+dist[v][j];
                    path[i][j] = path[v][j];
                }

    /* output the result...
    for( int v=0; v<verNum; ++v )
    {
        cout << "The " << v << "th vertex's shortest path: " << endl;
        for( int i=0; i<verNum; ++i )
        {
            if( dist2D[v][i] < g.MAXWEIGHT )
            {
                cout << i << ":\t" << dist2D[v][i] << "\t" << i << " <-- ";
                for( int j=path2D[v][i]; j!=v; j=path2D[v][j] )
                    cout << j << " <-- ";
                cout << v << endl;
            }
            else
                cout << i << ":\tMAX\tNo Path!" <<endl;
        }
        cout << endl;
    }
    */
}


/**
 * Reload the "<<" operator.
 */
template<typename Object, typename Weight>
ostream& operator<<( ostream &out, const AMGraph<Object,Weight> &g )
{
    int verNum = g.getVertexNumber(),
        edgeNum = g.getEdgeNumber();

    out << "This graph has " << verNum << " vertexes and " << edgeNum << " edges." << endl;
	for( int i=0; i<verNum; ++i )
	{
		for( int j=0; j<verNum; ++j )
		{
		    Weight tmp = g.getWeight( i, j );
		    if( tmp == g.MINWEIGHT )
                out << "MIN" << "\t";
            else if( tmp == g.MAXWEIGHT )
                out << "MAX" << "\t";
            else
                out << g.getWeight( i, j ) << "\t";
		}
		out << "\n";
	}

	return out;
}

 

测试文件:

 

/*****************************************************************************
 *                               amgraph_test.cpp
 *
 * Adjacency Matrix Based Undirected Graph testing.
 *
 * Zhang Ming, 2010-07
 *****************************************************************************/


#define BOUNDS_CHECK

#include <iostream>
#include "amgraph.h"


using namespace std;
using namespace itlab;


int main()
{
    AMGraph<char,int> g;

    g.insertVertex( 'A' );
    g.insertVertex( 'B' );
    g.insertVertex( 'C' );
    g.insertVertex( 'D' );
    g.insertVertex( 'E' );
    g.insertVertex( 'F' );
    cout << g << endl << endl;

    g.insertEdge( 'A', 'B', 50 );
    g.insertEdge( 'A', 'E', 70 );
    g.insertEdge( 'A', 'C', 10 );
    g.insertEdge( 'B', 'C', 15 );
    g.insertEdge( 'B', 'E', 10 );
    g.insertEdge( 'C', 'A', 20 );
    g.insertEdge( 'C', 'D', 15 );
    g.insertEdge( 'D', 'B', 20 );
    g.insertEdge( 'D', 'E', 35 );
    g.insertEdge( 'E', 'D', 30 );
    g.insertEdge( 'F', 'D', 3 );
    cout << g << endl << endl;

    int verNum = g.getVertexNumber(),
        start = g.getIndex( 'A' ),
        *dist = new int[verNum],
        *path = new int[verNum];
    g.dijkstra( start, dist, path );
    cout << "The Dijkstra algorithm for Single-Source Shortest Path." << endl;
    for( int i=0; i<verNum; ++i )
    {
        if( dist[i] < g.MAXWEIGHT )
        {
            cout << i << ":\t" << dist[i] << "\t" << i << " <-- ";
            for( int j=path[i]; j!=start; j=path[j] )
                cout << j << " <-- ";
            cout << start << endl;
        }
        else
            cout << i << ":\tMAX\tNo Path!" <<endl;
    }
    cout << endl << endl;

    int **dist2D,
        **path2D;
    makeMatrix( dist2D, verNum, verNum );
    makeMatrix( path2D, verNum, verNum );
    g.floyd( dist2D, path2D );
    cout << "The Floyd algorithm for All-Pairs Shortest Paths." << endl;
    for( int v=0; v<verNum; ++v )
    {
        cout << "The " << v << "th vertex's shortest path: " << endl;
        for( int i=0; i<verNum; ++i )
        {
            if( dist2D[v][i] < g.MAXWEIGHT )
            {
                cout << i << ":\t" << dist2D[v][i] << "\t" << i << " <-- ";
                for( int j=path2D[v][i]; j!=v; j=path2D[v][j] )
                    cout << j << " <-- ";
                cout << v << endl;
            }
            else
                cout << i << ":\tMAX\tNo Path!" <<endl;
        }
        cout << endl;
    }
    cout << endl;

    g.removeVertex( 'B' );
    cout << g << endl << endl;

    g.removeEdge( 'A', 'E' );
    g.removeEdge( 'F', 'D' );
    cout << g << endl << endl;

    g.removeVertex( 'B' );
    g.removeEdge( 'A', 'B' );
    g.removeEdge( 'E', 'C' );
    g.removeEdge( 'F', 'D' );

    cout << endl;
    return 0;
}

 

转载于:https://my.oschina.net/zmjerry/blog/6081

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值