隣接チェーンテーブル無方向図のC++実現
13708 ワード
ヘッダファイル:
実装ファイル:
テストファイル:
/*****************************************************************************
* graph.h
*
* Adjacency List Based Undirected Graph.
*
* This is a C++ template class for undirected graph with an adjacency list
* representation. It provedes the general operations for graph, such as
* insertVertex, removeVertex, insertEdge, removeEdge, getVertexNumber,
* getEdgeNumber, getData, getWeight, getNextDst, and so on.
*
* When debugging, use #define BOUNDS_CHECK above your "#include vector.h"
* line. When done debugging, comment out #define BOUNDS_CHECK for better
* performance.
*
* Zhang Ming, 2009-10
*****************************************************************************/
#ifndef GRAPH_H
#define GRAPH_H
#include <iostream>
#include <cstdlib>
#include <cassert>
#include <constants.h>
using namespace std;
namespace itlab
{
/**
* graph's edge
*/
template<typename Weight>
struct Edge
{
int dst;
Weight cost;
Edge<Weight> *next;
Edge( int d, Weight c, Edge<Weight> *p=NULL )
: dst(d), cost(c), next(p)
{ }
};
/**
* graph's vertex
*/
template<typename Object, typename Weight>
struct Vertex
{
Object data;
Edge<Weight> *adj;
Vertex( Object x=Object(), Edge<Weight> *p=NULL )
: data(x), adj(p)
{ }
};
/**
* adjacency list based graph
*/
template<typename Object, typename Weight>
class ALGraph
{
public:
explicit ALGraph( int n=INITSIZE );
~ALGraph();
int getVertexNumber() const;
int getEdgeNumber() const;
Object getData( int i ) const;
int getIndex( const Object &x ) 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 );
private:
int curSize;
int maxSize;
int edgeNum;
Vertex<Object, Weight> *vertexArray;
};
#include <graph-impl.h>
}
// namespace itlab
#endif
// GRAPH_H
実装ファイル:
/*****************************************************************************
* graph-impl.h
*
* Implementation for ALGraph class.
*
* Zhang Ming, 2009-10
*****************************************************************************/
/**
* constructors and destructor
*/
template<typename Object, typename Weight>
ALGraph<Object,Weight>::ALGraph( int n )
{
maxSize = n;
curSize = 0;
edgeNum = 0;
vertexArray = new Vertex<Object,Weight>[maxSize];
if( vertexArray == NULL )
{
cerr << "Out of memory!";
exit(1);
}
for( int i=0; i<maxSize; ++i )
vertexArray[i].adj = NULL;
}
template<typename Object, typename Weight>
ALGraph<Object,Weight>::~ALGraph()
{
for( int i=0; i<maxSize; ++i )
{
Edge<Weight> *p = vertexArray[i].adj;
while( p != NULL )
{
vertexArray[i].adj = p->next;
delete p;
p = vertexArray[i].adj;
}
}
delete []vertexArray;
}
/**
* Get the vertex number of the graph.
*/
template<typename Object, typename Weight>
int ALGraph<Object,Weight>::getVertexNumber() const
{
return curSize;
}
/**
* Get the edge number of the graph.
*/
template<typename Object, typename Weight>
int ALGraph<Object,Weight>::getEdgeNumber() const
{
return edgeNum;
}
/**
* Return the content of vertex "i".
*/
template<typename Object, typename Weight>
inline Object ALGraph<Object,Weight>::getData( int i ) const
{
#ifdef BOUNDS_CHECK
assert( 0 <= i );
assert( i < maxSize );
#endif
return vertexArray[i].data;
}
/**
* Return the index of vertex "x".
*/
template<typename Object, typename Weight>
int ALGraph<Object,Weight>::getIndex( const Object &x ) const
{
for( int i=0; i<curSize; ++i )
if( vertexArray[i].data == x )
return i;
return -1;
}
/**
* Return weight on the edge between vertex "x1" and "x2".
*/
template<typename Object, typename Weight>
Weight ALGraph<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
{
Edge<Weight> *p = vertexArray[v1].adj;
while( p != NULL && p->dst != v2 )
p = p->next;
if( p != NULL )
return p->cost;
else
{
cerr << "There is no edge between x1 and x2!" << endl;
return Weight(0);
}
}
}
/**
* Get the position of the next adjacency point of vertex "x".
*/
template<typename Object, typename Weight>
int ALGraph<Object,Weight>::getNextDst( const Object &x ) const
{
int i = getIndex(x);
if( i == -1 )
{
cerr << "There is no vertex x!" << endl;
return -1;
}
else
{
Edge<Weight> *p = vertexArray[i].adj;
if( p != NULL )
return p->dst;
else
return -1;
}
}
template<typename Object, typename Weight>
int ALGraph<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
{
Edge<Weight> *p = vertexArray[v1].adj;
while( p != NULL && p->dst != v2 )
p = p->next;
if( p != NULL && p->next != NULL )
return p->next->dst;
else
return -1;
}
}
/**
* Insert a new vertex "x". If the vertex array is full, then
* return false, else return true.
*/
template<typename Object, typename Weight>
void ALGraph<Object,Weight>::insertVertex( const Object &x )
{
if( curSize < maxSize )
vertexArray[curSize++] = Vertex<Object,Weight>( x, NULL );
else
cerr << "The vertex table is full!" << endl;
}
/**
* Remove the vertex "x".
*/
template<typename Object, typename Weight>
void ALGraph<Object,Weight>::removeVertex( const Object &x )
{
int i = 0,
v = getIndex(x);
if( v == -1 )
cerr << "There is no vertex x!" << endl;
else
{
Edge<Weight> *p, *r, *s;
while( vertexArray[v].adj != NULL )
{
p = vertexArray[v].adj;
i = p->dst;
r = vertexArray[i].adj;
s = NULL;
while( r != NULL && r->dst != v )
{
s = r;
r = r->next;
}
if( s != NULL )
s->next = r->next;
else
vertexArray[i].adj = r->next;
delete r;
vertexArray[v].adj = p->next;
delete p;
edgeNum--;
}
vertexArray[v] = vertexArray[--curSize];
vertexArray[curSize].adj = NULL;
p = vertexArray[i].adj;
while( p != NULL )
{
r = vertexArray[p->dst].adj;
while( s != NULL )
{
if( s->dst == curSize )
{
s->dst = v;
break;
}
else
s = s->next;
}
p = p->next;
}
}
}
/**
* 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 ALGraph<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
{
Edge<Weight> *p = vertexArray[v1].adj,
*q = NULL;
while( p != NULL && p->dst != v2 )
p = p->next;
if( p != NULL )
cerr << "The edge is already existence!" << endl;
p = new Edge<Weight>( v2, c, vertexArray[v1].adj );
vertexArray[v1].adj = p;
q = new Edge<Weight>( v1, c, vertexArray[v2].adj );
vertexArray[v2].adj = q;
edgeNum++;
}
}
/**
* Remove the edge (x1,x2).
*/
template<typename Object, typename Weight>
void ALGraph<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
{
Edge<Weight> *p = vertexArray[v1].adj,
*q = NULL,
*r = p;
while( p != NULL && p->dst != v2 )
{
q = p;
p = p->next;
}
if( p != NULL )
{
if( p == r )
vertexArray[v1].adj = p->next;
else
{
q->next = p->next;
delete p;
}
}
else
cerr << "There is no such edge!" << endl;
p = vertexArray[v2].adj;
q = NULL;
r = p;
while( p->dst != v1 )
{
q = p;
p = p->next;
}
if( p == r )
vertexArray[v2].adj = p->next;
else
{
q->next = p->next;
delete p;
}
edgeNum--;
}
}
/**
* Reload the "<<" operator.
*/
template<typename Object, typename Weight>
ostream& operator<<( ostream &out, const ALGraph<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 )
{
Object x1 = g.getData(i);
out << x1 << " : ";
int j = g.getNextDst(x1);
if( j != -1 )
{
Object x2 = g.getData(j);
out << "( " << x1 << ", " << x2 << ", " << g.getWeight(x1,x2) << " )" << " ";
do
{
j = g.getNextDst( x1, x2 );
if( j != -1 )
{
x2 = g.getData(j);
out << "( " << x1 << ", " << x2 << ", " << g.getWeight(x1,x2) << " )" << " ";
}
else
break;
}
while( j != -1 );
}
out << endl;
}
return out;
}
テストファイル:
/*****************************************************************************
* graph_test.cpp
*
* Adjacency List Based Undirected Graph testing.
*
* Zhang Ming, 2009-10
*****************************************************************************/
#define BOUNDS_CHECK
#include <iostream>
#include <graph.h>
using namespace std;
using namespace itlab;
int main()
{
ALGraph<char, int> g( 5 );
g.insertVertex( 'A' );
g.insertVertex( 'B' );
g.insertVertex( 'C' );
g.insertVertex( 'D' );
cout << g << endl << endl;
g.insertEdge( 'A', 'B', 4 );
g.insertEdge( 'A', 'C', 2 );
g.insertEdge( 'B', 'D', 3 );
cout << g << endl << endl;
g.removeEdge( 'A', 'B' );
cout << g << endl << endl;
g.removeVertex('B');
cout << g << endl << endl;
g.removeEdge( 'A', 'B' );
cout << g << endl << endl;
g.removeVertex('B');
cout << g << endl;
return 0;
}