图的表示和实现1(图的矩阵表示法)

邻接矩阵:

邻接矩阵是用矩阵来表示顶点之间的相邻关系的一种方法。A[i,j]=1则是图的边。若A[i,j]=0,则不是图的边。若G是网络则A[i,j] = wij;   wij表示边上的权值,若A[i,j]=0或无穷则计算机允许的大于所有边上权值的数。

邻接矩阵表示带权图类:

除了采用二维数组存储用于表示顶点间相邻关系的邻接矩阵外,通常还需要用一个顺序表来存储顶点信息。

vertexlist是一个顺序表,存储图的顶点集和,adjmatrix是一个动态二维数组,存储图的邻接矩阵,size表示二维数组容量,vertCount表示图的顶点数

#include<iostream>

using namespace std;

struct Edge  //带权值的边
{
  int start;  //边的起点
  int dest;  // 边的终点
  int weight;  //边的权值

  friend ostream& operator<<(ostream& out,Edge &e);
};

ostream& operator <<(ostream& out,Edge &e)
{
	out<<"("<<e.start<<","<<e.dest<<","<<e.weight<<")";
	return out;
}

#include "SeqQueue.h"

template<class T>
class AbstractGraph  //抽象图类
{
public:
	virtual int VertexCount() = 0;  //返回顶点数,纯虚构函数,由子类实现 
	virtual T Get(int i) = 0;  //返回顶点vi的数据域
	virtual int GetFirstNeighbor (int v) = 0;  // 返回顶点v的第一个邻接顶点的序号
	virtual int GetNextNeighbor(int v, int w) = 0;   //返回顶点v在w后的下一个邻接顶点的序号

	void DFSTraverse(int v);  //从顶点v出发对非连通图进行一次深度优先搜索遍历
	void BFSTraverse(int v);  // 从顶点v出发对非连通图进行一次广度优先搜索遍历

private:
	void depthfs(int v,bool visited[]);  //从顶点v出发的一次深度优先搜索遍历
	void breadthfs(int v,bool visited[]);  //从顶点v出发的一次广度优先搜索遍历
};


#include"Edge.h"  // 边类
#include"SequenceList.h"   //顺序表类
#include"AbstractGraph.h"  //抽象图类

template<class T>
class AdjMatrixGraph:public AbstractGraph<T>  //邻接矩阵表示的带权图类,继承抽象图类
{
private:
	SequenceList<T> vertexlist;  //顺序表存储图的顶点集和,已执行构造函数
	int **adjmatrix;  // 图的邻接矩阵,动态二维数组
	int size;  // 二维数组的容量
	int vertcount;   //顶点数,vertCount<=size
	void Initial(int size);  //初始化图的邻接矩阵表示
public:
	AdjMatrixGraph(int size = 10);  //构造方法,size指定二维数组的容量
	AdjMatrixGraph(T vertices [],int vertcount,Edge edges[],int edgeCounT);  //以顶点集和和边集和构造一个图

	~AdjMatrixGraph ();
	int VertexCount();  //返回顶点数
	T Get(int i);  //返回顶点vi的数据元素
	void InsertEdge(int i,int j,int weight);  //插入一条权值为weight的边

	bool InsertEdge(Edge edge);  //插入一条边
	friend ostream& operator <<(ostream& out,AdjMatrixGraph<T> &graph);  //输出图的顶点集合和邻接矩阵

	bool RemoveEdge(int i,int j);  //删除边指定顶点序号
	bool RemoveVertex(int v, T &old);  //删除序号为v的顶点及其相关联的边
	int GetFristNeighbor(int v);  //返回顶点v的第一个邻接顶点的序号
	int GetNextNeighbor(int v,int w);  // 返回v在w后的下一个邻接顶点的符号
	void MinSpanTree_prim(Edge *mst);  //构造带权图最小生成树的普里姆算法
	void ShortestPath(int v);  //以Dijkstra算法求带权图中顶点的单源最短路径
	void ShortestPa();   //以Floyd算法求带权图中每对顶点之间的最短路径
};

const int MAX_WEIGHT = 9999;//  最大权值
带权值的边结构体:

#include<iostream>

using namespace std;

struct Edge  //带权值的边
{
  int start;  //边的起点
  int dest;  // 边的终点
  int weight;  //边的权值

  friend ostream& operator<<(ostream& out,Edge &e);
};

ostream& operator <<(ostream& out,Edge &e)
{
	out<<"("<<e.start<<","<<e.dest<<","<<e.weight<<")";
	return out;
}

图的构造和析构函数:

template<class T>
AdjMatrixGraph<T>::~AdjMatrixGraph()  //顺序表vertexlist析构已由SeqList类实现
{
  for(int i=0;i<size;i++)  // 释放动态二维数组占用的内存空间
	  delete(adjmatrix[i]);
  delete(adjmatrix);
}

template<class T>
int AdjMatrixGraph<T>::VertexCount()  //返回顶点数
{
   return vertcount;
}

template<class T>
T AdjMatrixGraph<T>::Get(int i)
{
	return vertexlist.Get(i);
}

template<class T>
ostream& operator<<(ostream& out,AdjMatriGraph<T>&graph)
{
   out<<"顶点集合:"<<graph.vertexlist<<"领接矩阵:\n";
   int n = graph.vertcount;
   for(int i = 0;i<n;i++)
   {
       for(int j=0;j<n;j++)
		   if(graph.adjmatrix[i][j] == MAX_WEIGHT)
			   out<<"  无穷";
		   else
			   out<<"  "<<graph.adjmatrix[i][j];
	   out<<" \n";
   }
   return out;
}
图的插入操作:
插入一个顶点vertex,就是在顶点的顺序表vertexlist最后插入一个新的元素vertex,顺序表容量不足的情况下将自动扩充容量,同时根据二维数组的情况自动扩充邻接矩阵的容量。

template<class T>
void AdjMatrixGraph<T>::InsertVertex(T vertex)  //插入一个顶点
{
    vertexlist.insert(vertex);  //在顺序表最后插入一个元素
	vertcount++;
	if(vertcount>size)
	{
	   int **temp = adjmatrix;
	   adjmatrix = new int *[size*2];  //二叉树组容量扩充2倍
	   int i,j;
	   for(i=0;i<size;i++)
	   {
	     adjmatrix[i] = new int[size*2];
		 for(j = 0;j<size;j++)
			 adjmatrix[i][j] = temp[i][j];
		 for(j = size;j<size*2;j++)
			 adjmatrix[i][j] = MAX_WEIGHT;
	   }
	   for(i = size;i<size*2;i++)  // 初始化扩充的邻接矩阵
	   {
	      adjmatrix[i] = new int[size*2];
		  for(j = 0;j<size*2;j++)
			  adjmarix[i][j] = (i==j)?0:MAX_WEIGHT;
	   }
	   size*=2;
	}
}

template<class T>
bool AdjMatrixGraph<T>::InsertEdge(int i, int j, int weight)  //插入一条权值为weight的边  若该边已存在,则不插入
{
   if(i>=0&&i<vertcount&&j>=0&&j<vertcount&&i!=j&&adjmatrix[i][j]==MAX_WEIGHT)
   {
      adjmatrix[i][j] = weight;
	  return true;
   }
   return false;
}

template<class T>
bool AdjMatrixGraph<T>::InsertEdge(Edge edge)  //插入一条边
{
   return InsertEdge(edge.start,edge.dest,edge.weighT);
}

图的删除操作:
删除图的一个顶点,除了要在顶点顺序表中删除指定顶点,还要在邻接矩阵中删除与该顶点相关联的所有边。删除vi顶点实际上就是把该点后所有的点都往前移动一个位置,同时把邻接矩阵中,第i+1至n-1列的元素均向前移动。

删除邻接矩阵中的一条边:只要将邻接矩阵中的该边的权值设置为无穷即可

template<class T>
bool AdjMatrixGraph<T>::RemoveEdge(int i, int j)  //删除边成功返回true
{
   if(i>=0&&i<vertcount&&j>=0&&j<vertcount&&i!=j&&adjmatrix[i][j]!=MAX_WEIGHT)
   {
      adjmatrix[i][j] = MAX_WEIGHT;
	  return true;
   }
   return false;
}

删除邻接矩阵vi的顶点

template<class T>
bool AdjMatrixGraph<T>::RemoveVertex(int v, T &old)
{
   if(v>=0&&v<vertcount&&vertexlist.remove(v,old))
   {
     for(int i=v;i<vertcount-1;i++)
		 for(int j=0;j<vertcount;j++)
			 adjmatrix[i][j] = adjmatrix[i+1][j];  //元素向前一行移动

	 for(int j =v;j<vertcount-1;j++)
		 for(int i = 0;i<vertcount-1;i++)
			 adjmatrix[i][j] = adjmatrix[i][j+1];  //元素向前一列移动
	 vertcount--;
	 return true;
   }
   return false;
}

邻接矩阵性能分析:

一个有n个顶点,e条边的图,对应的邻接矩阵使用n的平方个元素存储了e条边的信息,当n较小且e较大时,邻接矩阵的存储效率是比较高的;反之,当n较大且e远小于n平方,矩阵变成稀疏矩阵,浪费的存储空间较多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值