一、邻接矩阵
图的邻接矩阵存储是用一个一维数组存储图中顶点的信息,用一个二维数组(称为邻接
矩阵)存储图中各顶点之间的邻接关系。
假设图G=(V,E)有n个顶点,则邻接矩阵是一个n×n的方阵
1、无向图的邻接矩阵
特点:
主对角线为0且一定是对称矩阵
邻接矩阵的第i行(或第i列)非零元素的个数为顶点i的度
邻接矩阵中相应位置的元素arc[i][j]若为1,则顶点i和j之间存在边
2、有向图的邻接矩阵
特点:
有向图的邻接矩阵不一定对称
邻接矩阵的第i行元素之和为顶点i的出度
邻接矩阵的第i列元素之和为顶点i的入度
邻接矩阵中相应位置的元素arc[i][j]若为1,则顶点i和j之间存在边
3、实现
const int MaxSize=10;
template <class T>
class Mgraph{
public:
MGraph(T a[ ], int n, int e );
~MGraph( )
void DFSTraverse(int v);
void BFSTraverse(int v);
……
private:
T vertex[MaxSize];
int arc[MaxSize][MaxSize];
int vertexNum, arcNum;
};
构造函数
template <class T>
MGraph::MGraph(T a[ ], int n, int e) {
vertexNum=n; arcNum=e;
for(i=0; i<vertexNum; i++)
vertex[i]=a[i];
for(i=0; i<vertexNum; i++) //初始化邻接矩阵
for(j=0; j<vertexNum; j++)
arc[i][j]=0;
for(k=0; k<arcNum; k++) {
cin>>i>>j; //边依附的两个顶点的序号
arc[i][j]=1; arc[j][i]=1; //置有边标志
}
}
深度优先遍历
int visited[MaxSize];
template <class T>
void MGraph::DFSTraverse(int v){
cout<<vertex[v]; visited [v]=1;
for (j=0; j<vertexNum; j++)
if (arc[v][j]==1 && visited[j]==0)
DFSTraverse( j );
}
广度优先遍历
int visited[MaxSize];
template <class T>
void MGraph::BFSTraverse(int v){
front=rear=-1; //假设采用顺序队列且不会发生溢出
int Q[MaxSize]; cout<<vertex[v]; visited[v]=1; Q[++rear]=v;
while (front!=rear) {
v=Q[++front];
for (j=0; j<vertexNum; j++)
if (arc[v][j]==1 && visited[j]==0 ) {
cout<<vertex[j]; visited[j]=1; Q[++rear]=j;
}
}
}
增加一个顶点
template <class T>
void MGraph<T>::InsertVex(int num,T name) {
if ( num<0|| num>vertexNum) throw "位置";
int row, col, numv;
numv = vertexNum-1;
vertexNum++;
for(int i=numv;i>=num;i--) vertex[i++]=vertex[i];
vertex[num]=name;
for(row=numv;row>=0;row--) {所有行上num列之后的列后移,增加一列,
for(col=numv;col>=num;col--) arc[row][col+1]=arc[row][col];
arc[row][num]=0;
}
for(row=numv;row>=num;row--)
for(col=0;col<=numv+1;col++) arc[row+1][col]=arc[row][col];
for(col=0;col<vertexNum;col++) arc[num][col]=0;
}
删除一个顶点
template <class T> void MGraph<T>::DeleteVex(int pos){
if ( pos<0|| pos>MaxSize) throw "位置";
int row, col;
int numv=vertexNum;
for(int i=pos;i<numv;i++) vertex[i]=vertex[i+1];
vertexNum--;
for(row=0;row<numv;row++) { //删除一列
for(col=pos;col<numv;col++) arc[row][col]=arc[row][col+1];
}
for(row=pos;row<numv;row++)
for(col=0;col<numv;col++)
arc[row][col]=arc[row+1][col];
}
}
插入一条边
template <class T>
void MGraph<T>::InsertArc(int i, int j)
{
if ( i>MaxSize|| j>MaxSize) throw "位置";
arc[i][j]=1;
arc[j][i]=1;
}
删除一条边
template <class T>
void MGraph<T>::DeleteArc(int i, int j)
{
if ( i>MaxSize|| j>MaxSize) throw "位置";
arc[i][j]=arc[j][i]=0;
}
二、邻接表
1、
邻接表有两种结点结构:顶点表结点和边表结点。
顶点表 vertex firstedge
边表 adjvex next
vertex:数据域,存放顶点信息。
firstedge:指针域,指向边表中第一个结点。
adjvex:邻接点域,边的终点在顶点表中的下标。
next:指针域,指向边表中的下一个结点。
2、实现
struct ArcNode{
int adjvex;
ArcNode *next;
};
template <class T>
struct VertexNode{
T vertex;
ArcNode *firstedge;
};
const int MaxSize=10; //图的最大顶点数
template <class T>
class ALGraph
{
public:
ALGraph(T a[ ], int n, int e);
~ALGraph;
void DFSTraverse(int v);
void BFSTraverse(int v);
………
private:
VertexNode adjlist[MaxSize];
int vertexNum, arcNum;
};
构造函数
template <class T>
ALGraph::ALGraph(T a[ ], int n, int e)
{
vertexNum=n; arcNum=e;
for (i=0; i<vertexNum; i++)
{
adjlist[i].vertex=a[i];
adjlist[i].firstedge=NULL;
}
for (k=0; k<arcNum; k++)
{
cin>>i>>j;
s=new ArcNode; s->adjvex=j;
s->next=adjlist[i].firstedge;
adjlist[i].firstedge=s;
}
}
深度优先遍历
template <class T>
void ALGraph::DFSTraverse(int v){
cout<<adjlist[v].vertex; visited[v]=1;
p=adjlist[v].firstedge;
while (p!=NULL) {
j=p->adjvex;
if (visited[j]==0) DFSTraverse(j);
p=p->next;
}
}
广度优先遍历
template <class T>
void ALGraph::BFSTraverse(int v){
front=rear=-1;
cout<<adjlist[v].vertex; visited[v]=1; Q[++rear]=v;
while (front!=rear) {
v=Q[++front]; p=adjlist[v].firstedge;
while (p!=NULL) {
j= p->adjvex;
if (visited[j]==0) {
cout<<adjlist[j].vertex; visited[j]=1; Q[++rear]=j;
}
p=p->next;
}
}
}
4、十字链表的结点结构
顶点表结点 vertex firstin firstout
边表结点 tailvex headvex headlink taillink
vertex:数据域,存放顶点信息;
firstin:入边表头指针;
firstout:出边表头指针;
tailvex:弧的起点在顶点表中的下标;
headvex:弧的终点在顶点表中的下标;
headlink:入边表指针域;
taillink:出边表指针域。
5、边集数组
利用两个一维数组
一个数组存储顶点信息,另外一个数组存储边及其权。
数组分量包含三个域:边所依附的两个顶点,权值
各边在数组中的次序可以任意。
实现
Struct edge
{
int i;
int j;
int weight;
}
将邻接矩阵转化成边集数组
edge edges[M];//边的数据结构类型的变量
for ( i = 0; i < G->vexnum; i++) {
for (j = 0; j <= G->vexnum; j++) {
if (G->arc[i][j] == 1) {
edges[k].begin = i;
edges[k].end = j;
// edges[k].weight = G->arc[i][j];
k++;
}
}
}