图的邻接矩阵表示

一、基本概念

1、图的定义

图G由两个集合顶点集V和边集E组成,记为G = (V , E)

2、邻接矩阵

(1)表示顶点之间相邻关系的矩阵叫邻接矩阵。具有n个顶点的图G=(V,E)是具有下列性质的n阶方阵:

A[i][j]=1,若(vi,vj)或<vi,vj>是E(G)中的边;

A[i][j]=0,若(vi,vj)或<vi,vj>不是E(G)中的边;

(2)若G是网络,则邻接矩阵可定义为:

A[i][j]=wij,若(vi,vj)或<vi,vj>是E(G)中的边;

A[i][j]= ,若(vi,vj)或<vi,vj>不是E(G)中的边;

邻接矩阵对有向图和无向图都适用,对带权图和非权图同样适用。

无向图的邻接矩阵显然为对称矩阵

3、顶点的度

在无向图中顶点V的度定义为以该顶点为一个端点的边的数目,称为顶点的度

若G是有向图,则v的出度是以v为始点的边的个数,v的入度是以v为终点的边的个数。

借助邻接矩阵,可以很容易求出图中顶点的度。

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

(2)有向图-邻接矩阵第i行的非零元素的个数为顶点Vi的出度;第i列的非零元素的个数为顶点Vi的入度

二、代码实现

下面要给出的代码,是以无向权图为例子。对于无向非权图,有向图权图,有向非权图,对插入删除顶点和边的代码做适量修改即可。

(1)  graph.h头文件

//graph.h
#include <climits>
#include <vector>
#include <fstream>

using namespace std;

template<typename T>
class Graph
{
	private:
		//int max_size ;		//最大顶点数 
		vector<T> vertexList;	//顶点表
		vector< vector<int> > edge;//邻接矩阵
		//int currentEdges;		//当前边数	
		
		bool findVertex(const T& v);
		int getVertexPosition(const T& v);
		
	public:
		
//		Graph();		
		bool isEmpty();
		void printGraph();		
		int getNumberOfVertex();
		int getWeight(const T& v1, const T& v2);
		int getFirstNeighbor(int v);
		int getNextNeighbor(int v1,int v2);
		
		void insertVertex(const T& v);
		void deleteVertex(const T& v);
		void insertEdge(const T& v1, const T& v2, int w);
		void deleteEdge(const T& v1, const T& v2);
		
		void readGraph(string fileName);
};

//以矩阵的形式输出图 
template <typename T>
void Graph<T>:: printGraph()
{
	for(int i=0; i<vertexList.size(); i++)
	{
		cout<<vertexList[i]<<": [ ";
		for(int j=0; j<vertexList.size(); j++)
		{
			if(edge[i][j] < INT_MAX)
				cout<<edge[i][j]<<" ";
			else
				cout<<" ∞"<<" ";
		}
		cout<<"]"<<endl;
	}
	cout<<endl<<endl;
}

//检测图是否为空
template <typename T>
bool Graph<T>:: isEmpty()
{
	return vertexList.empty();
}

//返回图的顶点个数
template <typename T>
int Graph<T>:: getNumberOfVertex()
{
	return vertexList.size();
}

//返回顶点vertex在顶点表中的位置(序号)
template <typename T>
int Graph<T>:: getVertexPosition(const T& v)
{
	for(int i=0; i<vertexList.size(); i++)
	{
		if(vertexList[i] == v)//
		{
			return i;
		}
	}
	return -1;
}

//检查顶点vertex是否已在顶点表中
template <typename T>
bool Graph<T>:: findVertex(const T& v)
{
	if(getVertexPosition(v) != -1)
	{
		return true;
	}
	return false;	
}

//返回指定边的权值
template <typename T>
int Graph<T>:: getWeight(const T& v1, const T& v2)
{
	int pos1 = getVertexPosition(v1);
	int pos2 = getVertexPosition(v2);
	
	if(pos1 != -1 && pos2 != -1)
		return edge[pos1][pos2];
	else
		return INT_MAX;//实际应该进行异常处理 
}

//返回序号为v的顶点的第一个邻接顶点的序号
template <typename T>
int Graph<T>:: getFirstNeighbor(int v)
{
	for(int i=0; i<vertexList.size(); i++)
	{
		if(edge[v][i] > 0 && edge[v][i] < INT_MAX)
		{
			return i;
		}
	}
	return -1;
}

//返回序号为v1的顶点相对于序号为v2的顶点的下一个邻接顶点的序号
template <typename T>
int Graph<T>:: getNextNeighbor(int v1,int v2)
{
	if(v1 != -1 && v2 != -1)
	{
		for(int i = v2+1; i<vertexList.size(); i++)
		{
			if(edge[v1][i] > 0 && edge[v1][i] < INT_MAX)
			{
				return i;
			}
		}
	}
	return -1;
}

//插入一个顶点
template <typename T>
void Graph<T>:: insertVertex(const T& v)
{
	if(findVertex(v))//已存在该顶点 
		return;
	//增加列 
	for(int i=0; i<vertexList.size(); i++)
	{
		edge[i].push_back(INT_MAX);
	}
	//增加行
	vector<int> column(vertexList.size(), INT_MAX);
	column.push_back(0);
	edge.push_back(column);
	//加入顶点表 
	vertexList.push_back(v); 
}

/*在图中删去顶点v和所有与它相关联的边
*删除第pos行和第pos列 
*然后从顶点表中删除顶点 
*/
template <typename T>
void Graph<T>:: deleteVertex(const T& v)
{
	int pos = getVertexPosition(v);
	
	if(pos == -1)
		return;

	//删除第pos列 
	for(int i=0; i<vertexList.size(); i++)
	{
		edge[i].erase(edge[i].begin() + pos);
	}
	//删除第pos行
	edge.erase(edge.begin() + pos);
	//从顶点表中删除
	vertexList.erase(vertexList.begin() + pos);	  
}

/*插入一条边(v1,v2),边权值为w
 *插入之前顶点已存在 
*/
template <typename T>
void Graph<T>:: insertEdge(const T& v1, const T& v2, int w)
{
	int pos1 = getVertexPosition(v1);
	int pos2 = getVertexPosition(v2);
	
	if(pos1 != -1 && pos2 != -1)
	{
		edge[pos1][pos2] = w;
		edge[pos2][pos1] = w;
	}
}

/*在图中删去边
 *与删除的边关联的两个顶点已存在 
*/
template <typename T>
void Graph<T>:: deleteEdge(const T& v1, const T& v2)
{
	if(v1 == v2)
		return;
		
	int pos1 = getVertexPosition(v1);
	int pos2 = getVertexPosition(v2);
	
	if(pos1 != -1 && pos2 != -1)
	{
		edge[pos1][pos2] = INT_MAX;
		edge[pos2][pos1] = INT_MAX;
	}
}

//从文件中的数据构造图
template <typename T>
void Graph<T>:: readGraph(string fileName)
{
	int vertexNumber;
	T vertex;
	T v1,v2;
	int weight;
	
	ifstream in(fileName.c_str(),ios_base::in);
	if(!in)
	{
		cout<<"file open error!"<<endl;
		exit(1);
	}
	in>>vertexNumber;
	for(int i=0; i<vertexNumber; i++)
	{
		in>>vertex;
		insertVertex(vertex);//插入顶点
	}
	while(in>>v1>>v2>>weight)
	{
		insertEdge(v1, v2, weight);//插入边 
	}
} 

(2)  测试程序

#include <cstdlib>
#include <iostream>
#include <string>

#include "graph.h"

int main(int argc, char *argv[])
{
	Graph<string> g;
	string fileName = "graph.txt";
	
	g.readGraph(fileName);
//	//插入顶点 
//	g.insertVertex("beijing");
//	g.insertVertex("shanghai");
//	g.insertVertex("guangzhou");
//	g.insertVertex("shenzhen");	
//	//插入边 
//	g.insertEdge("beijing", "shanghai", 1000);
//	g.insertEdge("beijing", "guangzhou", 2000);
//	g.insertEdge("beijing", "shenzhen", 2100);
//	g.insertEdge("shanghai", "guangzhou", 500);
//	g.insertEdge("shanghai", "shenzhen", 600);
//	g.insertEdge("guangzhou", "shenzhen", 100);
	
	cout<<"after insert vertex and edges: "<<endl;
	g.printGraph();
	
	//删除边 	 
	g.deleteEdge("beijing", "shenzhen");
	g.deleteEdge("shanghai", "shenzhen");
	
	cout<<"after delete edges: "<<endl;
	g.printGraph();
	
	//删除顶点
//	g.deleteVertex("shanghai");
	g.deleteVertex("shenzhen");
	
	cout<<"after delete vertex: "<<endl;
	g.printGraph();
	
    system("PAUSE");
    return EXIT_SUCCESS;
}

注:

(1)图描述的是北上广深城市之间的距离,权值是随便写的,可以无视。

(2)graph.txt内容

4
beijing shanghai guangzhou shenzhen
beijing shanghai 1000
beijing guangzhou 2000
beijing shenzhen 2100
shanghai guangzhou 500
shanghai shenzhen 600
guangzhou shenzhen 100

参考资料:

[1]《数据结构》刘大有 唐海鹰等著 高等教育出版社

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值