1、基本思想
-用一维数组存储顶点:描述顶点相关的数据
-用二维数组存储边:描述顶点间的关系和权
2、邻接矩阵法
-设图A = (V, E)是一个有n个顶点的图,图的邻接矩阵为
Edge[n] [n] , 则:
注:
解决工程问题时,习惯于对图中的每个顶点进行编号
当不需要权值时,取W非空表示结点间有连接
邻接矩阵法示例一
-无向图的邻接矩阵是对称的
邻接矩阵法示例二
- 有向图的邻接矩阵可能是不对称的
3、设计与实现
问题:
如何具体表示顶点集数组?
如何具体表示边集数组?
4、实现方式一
- 直接使用数组表示顶点集和边集 (不推荐)
分析下面代码的效率
问题
-构造效率低下
图对象初始化时,频繁调用顶点类型和边类型的构造函数
-空间使用率低下
图对象占用大量空间,而大多数空间处于闲置状态
-无法表示空值
无法用统一的方式表示边为空的情形5、实现方式二
- 使用指针数组表示顶点集和边集
问题的解决
-构造效率
初始化图对象时,只需要将数组元素赋值为空
-空间使用率
顶点数据元素和边数据元素在需要时动态创建
-空值的表示
任意的顶点类型和边类型都使用NULL表示空值6、编程实验
图的邻接矩阵结构 class MatrixGraph;
#ifndef MATRIXGRAPH_H
#define MATRIXGRAPH_H
#include "Graph.h"
#include "Exception.h"
#include "DynamicArray.h"
namespace DTLib
{
template < int N, typename V, typename E > //N : 图中顶点的个数 V : 与顶点关联数据元素类型 //E : 权值类型
class MatrixGraph : public Graph<V,E>
{
protected:
V* m_vertexes[N]; //每一个成员指向与顶点相关联数据元素
E* m_edges[N][N]; //邻接矩阵
int m_eCount; //当前图的边数
public:
MatrixGraph() //当前图没有任何顶点与数据元素相关联
{
for(int i=0;i<vCount();i++)
{
m_vertexes[i] = NULL;
for(int j=0;j<vCount();j++)
{
m_edges[i][j] = NULL;
}
}
m_eCount = 0;
}
V getVertex(int i) //获取顶点i相关联数据元素值
{
V ret;
if( !getVertex(i,ret) )
{
THROW_EXCEPTION(InvalidParameterException,"Index i is invalid ...");
}
return ret;
}
bool getVertex(int i,V& value)
{
bool ret = (0 <= i) && (i < vCount());
if(ret)
{
if(m_vertexes[i] != NULL)
{
value = *(m_vertexes[i]);
}
else
{
THROW_EXCEPTION(InvalidOperationException,"No value assigned to this vertex ...");
}
}
return ret;
}
bool setVertex(int i,const V& value)
{
bool ret = (0 <= i) && (i < vCount());
if( ret )
{
V* data = m_vertexes[i]; //保证图对象的内部状态不改变
if(data == NULL)
{
data = new V();
}
if(data != NULL)
{
*data = value;
m_vertexes[i] = data;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"No memory to store new vertex value ...");
}
}
return ret;
}
SharedPointer< Array<int> > getAdjacent(int i)//数组存的为与i邻接的顶点编号
{
DynamicArray<int>* ret = NULL;
if( (0 <= i) && (i < vCount()) )
{
int n = 0;
for(int j=0;j<vCount();j++)
{
if(m_edges[i][j] != NULL) //对于i的邻接顶点,可以遍历i行所有元素,注意i和j的含义
{
n++;
}
}
ret = new DynamicArray<int>(n);
if(ret != NULL)
{
for(int j=0,k=0;j<vCount();j++)
{
if(m_edges[i][j] != NULL)
{
ret->set(k++,j); //就为邻接顶点的编号
}
}
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"No memory to create ret object ...");
}
}
else
{
THROW_EXCEPTION(InvalidParameterException,"Index i is invalid ...");
}
return ret;
}
E getEdge(int i,int j) //获取顶点i,j间边权值
{
E ret;
if( !getEdge(i,j,ret) )
{
THROW_EXCEPTION(InvalidParameterException,"Index <i,j> is invalid ...");
}
return ret;
}
bool getEdge(int i,int j,E& value)
{
bool ret = (0 <= i)&&(i < vCount())&&
(0 <= j)&&(j < vCount());
if( ret )
{
if(m_edges[i][j] != NULL) //有权值
{
value = *(m_edges[i][j]);
}
else
{
THROW_EXCEPTION(InvalidOperationException,"No value assigned to this edge ...");
}
}
return ret;
}
bool setEdge(int i,int j,const E& value)
{
bool ret = (0 <= i)&&(i < vCount())&&
(0 <= j)&&(j < vCount());
if( ret )
{
E* ne = m_edges[i][j];
if(m_edges[i][j] == NULL)
{
ne = new E();
if(ne)
{
*ne = value;
m_edges[i][j] = ne;
m_eCount++;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"No memory store new edge ...");
}
}
else
{
*ne = value;
}
}
return ret;
}
bool removeEdge(int i,int j)
{
bool ret = (0 <= i)&&(i < vCount())&&
(0 <= j)&&(j < vCount());
if( ret )
{
E* toDel = m_edges[i][j];
m_edges[i][j] = NULL;
if(toDel != NULL)
{
m_eCount--;
delete toDel;
}
}
return ret;
}
int vCount()
{
return N;
}
int eCount()
{
return m_eCount;
}
int OD(int i)//i行不为空的数据元素即为出度
{
int ret = 0;
if( (0 <= i) && (i < vCount()) )
{
for(int j=0;j<vCount();j++)
{
if(m_edges[i][j] != NULL)
{
ret++;
}
}
}
else
{
THROW_EXCEPTION(InvalidParameterException,"Index i is invalid ...");
}
return ret;
}
int ID(int i) //i列数据元素不为0即为入度
{
int ret = 0;
if( (0 <= i) && (i < vCount()) )
{
for(int j=0;j<vCount();j++)
{
if(m_edges[j][i] != NULL)
{
ret++;
}
}
}
else
{
THROW_EXCEPTION(InvalidParameterException,"Index i is invalid ...");
}
return ret;
}
~MatrixGraph()//将每条边权值释放,与顶点关联数据元素释放
{
for(int i=0;i<vCount();i++)
{
for(int j=0;j<vCount();j++)
{
delete m_edges[i][j];
}
delete m_vertexes[i];
}
}
};
}
#endif // MATRIXGRAPH_H
main.cpp
#include <iostream>
#include "MatrixGraph.h"
using namespace std;
using namespace DTLib;
int main()
{
MatrixGraph<3,int,int> g;
g.setEdge(0,1,1);
g.setEdge(1,0,2);
g.setEdge(1,2,3);
cout << "vCount : " << g.vCount() << endl;
cout << "eCount : " << g.eCount() << endl;
cout << "ID(1) : " << g.ID(1) << endl;
cout << "OD(1) : " << g.OD(1) << endl;
cout << "TD(1) : " << g.TD(1) << endl;
cout << "W(0,1) : " << g.getEdge(0,1) << endl;
cout << "W(1,0) : " << g.getEdge(1,0) << endl;
cout << "W(1,2) : " << g.getEdge(1,2) << endl;
SharedPointer< Array<int> > aj = g.getAdjacent(1);
for(int i=0;i<aj->length();i++)
{
cout << (*aj)[i] << " ";
}
cout << "Delete Edge : " <<endl;
g.removeEdge(0,1);
cout << "eCount : " << g.eCount() << endl;
g.setVertex(0,100);
cout << "V(0) : " << g.getVertex(0) <<endl;
cout << "W(0,1) : " << g.getEdge(0,1) << endl;
return 0;
}
7、小结
邻接矩阵法使用数组对图相关的数据进行存储
一维数组存储顶点相关的数据(空表示无相关数据)
二维数组存储边相关的数据(空表示顶点间无连接)
代码实现时 使用指针数组进行数据的存储(提高效率)