图的表示--邻接矩阵

定定义

邻接 矩阵(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)[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改回UNVISITED
		graphMatrix.mark[i] = UNVISITED; 

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

	system("pause");
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值