您的位置:首页 > 其它

图的表示--邻接矩阵

2014-01-09 01:03 253 查看


定定义

邻接矩阵(Adjacency Matrix):是表示顶点之间相邻关系的矩阵。设G=(V,E)是一个图,其中V={v1,v2,…,vn}。G的邻接矩阵是一个具有下列性质的n阶方阵:

①对无向图而言,邻接矩阵一定是对称的,而且对角线一定为零(在此仅讨论无向简单图),有向图则不一定如此。

②在无向图中,任一顶点i的度为第i列所有元素的和,在有向图中顶点i的出度为第i行所有元素的和,而入度为第i列所有元素的和。

③用邻接矩阵法表示图共需要n^2个空间,由于无向图的邻接矩阵一定具有对称关系,所以扣除对角线为零外,仅需要存储上三角形或下三角形的数据即可,因此仅需要n(n-1)/2个空间。


2特点

无向图的邻接矩阵一定是对称的,而有向图的邻接矩阵不一定对称。因此,用邻接矩阵来表示一个具有n个顶点的有向图时需要n^2个单元来存储邻接矩阵;对有n个顶点的无向图则只存入上(下)三角阵中剔除了左上右下对角线上的0元素后剩余的元素,故只需1+2+...+(n-1)=n(n-1)/2个单元。

无向图邻接矩阵的第i行(或第i列)非零元素的个数正好是第i个顶点的度。

有向图邻接矩阵中第i行非零元素的个数为第i个顶点的出度,第i列非零元素的个数为第i个顶点的入度,第i个顶点的度为第i行与第i列非零元素个数之和。

用邻接矩阵表示图,很容易确定图中任意两个顶点是否有边相连。

以上内容来自度娘,基本上讲清楚了图的基本概念,接下就实现之:

Graph.h

#ifndef GRAPH_H
#define GRAPH_H

#define UNVISITED 0
#define VISITED 1
#define INFINITE 0xffffffff

//Edge类
class Edge
{
public://公开为public是为了算法的方便,实际工作应用中应为private
int weight;//weight是边的权
int to;//to是边的终点
int from;//from是边的始点

public:
Edge()
{
weight = 0;
to = -1;
from = -1;
}

Edge(int w,int t,int f) : weight(w),to(t),from(f)
{

}

bool operator < (const Edge &edge)
{
return this->weight < edge.weight;
}

bool operator > (const Edge &edge)
{
return this->weight > edge.weight;
}

bool operator == (const Edge &edge)
{
return this->weight == edge.weight;
}

bool operator <= (const Edge &edge)
{
return this->weight <= edge.weight;
}

bool operator >= (const Edge &edge)
{
return this->weight >= edge.weight;
}
};

class Graph
{
public:
int numVertex;             //图的顶点的个数
int numEdge;				//图的边的数目
int *mark;					/*Mark指针指向保存有图的顶点的标志位的数组,标志位用来标记某顶点是否被访问过*/
int *indegree;				//Indegree指针指向保存有图的顶点的入度的数组

Graph(int numVert)
{		//构造函数
numVertex = numVert;      //确定图的顶点的个数
numEdge = 0;				//确定图的边的数目
indegree = new int[numVertex]; /*为保存图的顶点的入度申请数组,indegree为数组指针*/
mark = new int[numVertex];	 /*为图的顶点的标志位申请数组,Mark为数组指针*/

for (int i = 0; i < numVertex; i++)  {	/*确定图的顶点的标志位和入度,即所有顶点的标志位初始化为未被访问过,入度初始化为0*/
mark[i] = UNVISITED;
indegree[i] = 0;
}
}

~Graph()
{
delete []mark;
delete []indegree;
}

virtual Edge firstEdge(int oneVertex)// 返回与顶点oneVertex相关联的第一条边
{
Edge edge;
edge.from = oneVertex;
edge.to = -1;
return edge;
}

virtual Edge nextEdge(Edge preEdge)// 返回与边PreEdge有相同关联顶点的下一条边
{
return preEdge;
}

int verticesNum() //返回图的顶点个数
{
return numVertex;
}

int edgesNum() //返回图的边数
{
return numEdge;
}

int fromVertex(Edge oneEdge) // 返回oneEdge的始点
{
return oneEdge.from;
}

int toVertex(Edge oneEdge) // 返回oneEdge的终点
{
return oneEdge.to;
}

int weight(Edge oneEdge) // 返回oneEdge的权值
{
return oneEdge.weight;
}

bool isEdge(Edge oneEdge)//如果oneEdge是边则返回TRUE,否则返回FALSE
{
if(oneEdge.weight > 0 && oneEdge.weight < INFINITE && oneEdge.to >= 0)
{
return true;
}
else
{
return false;
}
}

virtual void setEdge(int from, int to, int weight) = 0;
virtual void delEdge(int from, int to) = 0;

};

#endif


GraphMatrix.h

#include "Graph.h"
#include <iostream>
#include <queue>
using std::cout;
using std::cin;
using std::endl;
using std::queue;

#define N 5 // 定义图的顶点数

class GraphMatrix : public Graph
{
int ** matrix; //指向相邻矩阵的指针

public:
GraphMatrix(int numVert) : Graph(numVert)
{
int i, j;			//i, j作为for循环中的计数器
matrix = (int **)new int*[numVertex]; /*申请matrix数组,该数组有numVertex个元素,每个元素是整型指针类型*/

for (i = 0; i < numVertex; i ++)		/*matrix数组的每个元素,都指向一个具有numVertex个元素的数组*/
matrix[i] = new int[numVertex];

for (i = 0; i < numVertex; i++)       /*相邻矩阵的所有元素都初始化为0,如果矩阵元素matrix[i][j]不为0,则表明顶点i与顶点j之间有一条边,边的权即为matrix[i][j]的值*/
for (j = 0; j < numVertex; j ++)
matrix[i][j] = 0;

}

~GraphMatrix()
{
for(int i = 0; i < numVertex; i++)
{
delete [] matrix[i];//释放每个matrix[i]申请的空间
}
delete [] matrix;//释放matrix指针指向的空间
}

virtual Edge firstEdge(int oneVertex)// 返回与顶点oneVertex相关联的第一条边
{
Edge edge;
edge.from = oneVertex;//将顶点oneVertex作为边edge的始点
edge.to = -1;

/* 下面寻找第一个使得matrix[oneVertex][i]
不为0的i值,那么边(oneVertex,i)或者
弧<oneVertex,i>即为顶点oneVertex
的第一条边,将顶点i作为边medge的终点边edge
的权为矩阵元素matrix[oneVertex][i]的值*/

for(int i = 0; i < numVertex; i++)
{
if(matrix[oneVertex][i] != 0)
{
edge.to = i;
edge.weight = matrix[oneVertex][i];
break;
}
}
return edge;
}

virtual Edge nextEdge(Edge preEdge)// 返回与边PreEdge有相同关联顶点的下一条边
{
Edge edge;
edge.from = preEdge.from;
edge.to = -1;

//如果preEdge.to+1>=numVertex,那么就不存在下一条边了
if(preEdge.to < numVertex)
{
for(int i = preEdge.to + 1; i < numVertex; i++)
{
/*寻找下一个使得//matrix[preEdge.from][i]不为0的i值,那么
(preEdge.from,i)或者<preEdge.from,i>即为顶点preEdge.from的下一条边*/
if(matrix[preEdge.from][i] != 0)
{
edge.to = i;
edge.weight = matrix[preEdge.from][i];
break;
}
}
}

/*如果找到了顶点preEdge.from的下一条边,则返回的edge确实是一条边;
如果没有找到顶点preEdge.from的下一条边,则edge的成员变量to为-1,
根据IsEdge函数判断可知edge不是一条边*/

return edge;
}

void setEdge(int from, int to, int weight)
{
/*如果matrix[from][to]<=0,则边(from,to) 或者<from,to>
将是新增的一条边,否则该边已经存在(现在只是对该边进行修改)*/

if(matrix[from][to] <= 0)
{
numEdge++;
indegree[to]++;
}

matrix[from][to] = weight;
}

void delEdge(int from, int to)
{
/*如果matrix[from][to]>0,则边(from,to)或者<from,to>确实存在,
否则该边实际上并不存在(从而不必对图的边数和顶点to的入度进行修改)*/

if(matrix[from][to] > 0)
{
numEdge--;
indegree[to]--;
}

matrix[from][to] = 0;
}

// 函数功能:初始化图
void initGraph(GraphMatrix &graphM,int (*A)
,int n)
{
for (int i = 0; i < n; i ++)
{
for (int j = 0; j < N; j ++)
{
if (A[i][j] > 0)
graphM.setEdge(i, j, A[i][j]);
}
}

}

void DFS( GraphMatrix &graph,int vertex)
{
graph.mark[vertex] = VISITED;
visit(graph,vertex);
for(Edge edge = graph.firstEdge(vertex); graph.isEdge(edge); edge = graph.nextEdge(edge))
{
if(graph.mark[graph.toVertex(edge)] == UNVISITED)
{
DFS(graph,graph.toVertex(edge));
}
}
}

void BFS( GraphMatrix &graph,int vertex)
{
queue<int> q;                    // 初始化广度优先周游要用到的队列
q.push(vertex);
while(!q.empty())
{
int v = q.front();
q.pop();
if(graph.mark[v] == UNVISITED )
{
visit(graph,v);
graph.mark[v] = VISITED;//标记该顶点已访问

// 该顶点邻接到的每一个未访问顶点都入队
for(Edge edge = graph.firstEdge(v); graph.isEdge(edge); edge = graph.nextEdge(edge))
{
if(graph.mark[graph.toVertex(edge)] == UNVISITED)
{
q.push(graph.toVertex(edge));
}
}
}
}
}

void visit(const GraphMatrix &graph,int vertex)
{
cout << "V:" << vertex << "\t";
}
};


测试代码:

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

int A

= {
//        V0 V1 V2 V3 V4
/*V0*/    0, 0, 1, 1, 0,
/*V1*/    0, 0, 0, 1, 1,
/*V2*/    1, 0, 0, 1, 1,
/*V3*/    1, 1, 1, 0, 0,
/*V4*/    0, 1, 1, 0, 0,};      //北大张铭《数据结构与算法》图7.2中G1表示的无向图

int main()
{
GraphMatrix graphMatrix(N);              // 建立图
graphMatrix.initGraph(graphMatrix, A,N); // 初始化图
cout << "DFS: ";
graphMatrix.DFS(graphMatrix, 0);
cout << endl;

for (int i = 0; i < graphMatrix.verticesNum(); i++) //把Mark改回UNVISITED
graphMatrix.mark[i] = UNVISITED;

cout << "BFS: ";
graphMatrix.BFS(graphMatrix, 0);
cout << endl;

system("pause");
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: