图的表示--邻接矩阵
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; }
相关文章推荐
- 19.图的存储表示----邻接矩阵表示法
- 数据结构-图的邻接矩阵表示
- 数据结构之图(C++)--邻接矩阵表示(一)
- 【数据结构】邻接矩阵表示法的图的深度广度优先遍历递归和非递归遍历
- 第七章(1).图的数组(邻接矩阵)存储表示
- 图的邻接矩阵和邻接链表表示
- 用邻接矩阵表示无向图 并输出每个结点的度数
- 数据结构 学习笔记(七):图(上):图的表示方法(邻接表,邻接矩阵),遍历(DFS,BFS)
- js 数据结构中邻接矩阵的图的直观表示
- 有向图的强连通分量(邻接矩阵图表示法)
- 算法(12)图的表示——邻接链表和邻接矩阵
- 邻接矩阵表示图的创建
- 图的邻接矩阵表示以及深度、广度优先遍历
- 图(有向图,无向图)的邻接矩阵表示C++实现(遍历,拓扑排序,最短路径,最小生成树) Implement of digraph and undigraph using adjacency matrix
- 图的邻接矩阵表示法
- 数据结构——邻接矩阵表示的图的Floyd算法
- 图的邻接矩阵表示及插入删除等操作
- 简单的图邻接矩阵表示
- 图的递归深度遍历(邻接矩阵表示)
- 图算法 图的表示(邻接表和邻接矩阵)和拓扑排序