图的表示--邻接矩阵

来源:互联网 发布:《linux就该这么学》 编辑:程序博客网 时间:2024/05/19 21:59

定定义

邻接矩阵(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是为了算法的方便,实际工作应用中应为privateint 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)[N],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[N][N] = {//        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改回UNVISITEDgraphMatrix.mark[i] = UNVISITED; cout << "BFS: ";graphMatrix.BFS(graphMatrix, 0);cout << endl;system("pause");return 0;}


0 0