2018-12-5更新
邻接矩阵分为有向图邻接矩阵和无向图邻接矩阵,矩阵元素可以仅表示相应的边是否存在,也可表示相应边的权值。
若是有向带权图的邻接矩阵,看到两种表示法,一种是不存在边的两个顶点i,j,matrix[i][j]=0或者+∞;另一种是matrix[i][i]=0,不存在边的两个顶点i,j,matrix[i][j]=+∞(i!=j)。
具体采用哪种方法是根据实际需求来的。为了方便Dijkstra算法,以下代码修改为上述第二种邻接矩阵。
--------------------------------------------------------------------------------------------------------------------------------------
2018-12-4更新
增添了memset函数对标记数组mark重置
--------------------------------------------------------------------------------------------------------------------------------------
- 说明
- 基于邻接矩阵实现的图
一、说明
1、以下代码实现的图,顶点为0到n-1(n为顶点数)(整数),边权为大于0的整数,邻接矩阵matrix[i][j]记录的是顶点i到顶点j的边权(大于0),若无边则为0。有向图。
2、以下代码仅供参考
二、基于邻接矩阵实现的图
1、Graph.h
#include<iostream>
using namespace std;
#include"Queue.h"
#ifndef _Graph
#define _Graph
namespace wangzhe
{
class Graph
{
private:
void operator = (const Graph&) {}
Graph(const Graph&) {}
public:
Graph() {}//构造函数
virtual ~Graph() {}//析构函数
virtual int n() =0;//顶点数目
virtual int e() =0;//边数目
virtual int first(int v) =0;//与顶点v关联的第一条边
virtual int next(int v,int w) =0;//与顶点v关联的在顶点w后的下一条边
virtual void clear()=0;//销毁一个图
virtual bool setEdge(int v1,int v2,int wght) =0;//设边权
virtual bool delEdge(int v1,int v2) =0;//删除边
virtual bool isEdge(int i,int j) =0;//判断是否有边
virtual int weight(int v1,int v2) =0;//v1-v2边的边权
virtual int getMark(int v) =0;//返回标记信号
virtual void setMark(int v,int val) =0;//标记数组中做标记
virtual void BFS(Graph* G,int start,Queue<int>* Q) =0;//广搜
virtual void DFS(Graph *G,int v) =0;//深搜
};
}
#endif
2、graphm.h
#include<iostream>
using namespace std;
#include"Graph.h"
#include"Queue.h"
#include"AQueue.h"
#include"AQueue.cpp"
#ifndef _Graphm
#define _Graphm
namespace wangzhe
{
class Graphm:public Graph
{
private:
int numVertex,numEdge;
int **matrix;
int *mark;
public:
Graphm();
~Graphm();
void Init(int n);
int n();
int e();
int first(int v);
int next(int v,int w);
void clear();
bool setEdge(int v1,int v2,int wt);
bool delEdge(int v1,int v2);
bool isEdge(int i,int j);
int weight(int v1,int v2);
int getMark(int v);
void setMark(int v,int val);
void memset();//重置mark数组
void BFS(Graph* G,int start,Queue<int>* Q);
void DFS(Graph *G,int v);
void print();//输出邻接矩阵
};
}
#endif
3、Graphm.cpp
#include<iostream>
#include<iomanip>
#define UNVISITED 0
#define VISITED 1
#define INF 1<<30
using namespace std;
#include"Graphm.h"
namespace wangzhe
{
Graphm::Graphm()
{
}
Graphm::~Graphm()
{
clear();
}
void Graphm::Init(int n)
{
numVertex=n;
numEdge=0;
mark=new int[n];
for(int i=0;i<numVertex;i++)
mark[i]=UNVISITED;
matrix=(int**) new int*[numVertex];
for(int i=0;i<numVertex;i++)
matrix[i]=new int[numVertex];
for(int i=0;i<numVertex;i++)
for(int j=0;j<numVertex;j++)
{
if(i==j) matrix[i][j]=0;
else matrix[i][j]=INF;
}
}
int Graphm::n()
{
return numVertex;
}
int Graphm::e()
{
return numEdge;
}
int Graphm::first(int v)
{
for(int i=0;i<numVertex;i++)
if(matrix[v][i]!=INF&&matrix[v][i]!=0) return i;
return numVertex;
}
int Graphm::next(int v,int w)
{
for(int i=w+1;i<numVertex;i++)
if(matrix[v][i]!=INF&&matrix[v][i]!=0) return i;
return numVertex;
}
void Graphm::clear()
{
delete [] mark;
mark=NULL;//释放后置空
for(int i=0;i<numVertex;i++)
delete [] matrix[i];
delete [] matrix;
matrix=NULL;//释放后置空
}
bool Graphm::setEdge(int v1,int v2,int wt)
{
if(wt<=0)
{
cout<<"Illegal weight value\n";
return false;
}
if(v1==v2||v1<0||v2<0||v1>=numVertex||v2>=numVertex)
{
cout<<"Illegal vertex\n";
return false;
}
if(matrix[v1][v2]==INF) numEdge++;
matrix[v1][v2]=wt;
return true;
}
bool Graphm::delEdge(int v1,int v2)
{
if(v1<0||v2<0||v1>=numVertex||v2>=numVertex||v1==v2)
{
cout<<"Illegal vertex\n";
return false;
}
if(matrix[v1][v2]!=INF) numEdge--;
matrix[v1][v2]=INF;
return true;
}
bool Graphm::isEdge(int i,int j)
{
if(i==j||matrix[i][j]==INF) return false;
return true;
}
int Graphm::weight(int v1,int v2)
{
if(v1<0||v2<0||v1>=numVertex||v2>=numVertex||v1==v2)
{
cout<<"Illegal vertex\n";
return INF;
}
return matrix[v1][v2];
}
int Graphm::getMark(int v)
{
return mark[v];
}
void Graphm::setMark(int v,int val)
{
mark[v]=val;
}
void Graphm::memset()
{
for(int i=0;i<numVertex;i++)
mark[i]=UNVISITED;
}
void Graphm::BFS(Graph* G,int start,Queue<int>* Q)
{
Q->enqueue(start);
G->setMark(start,VISITED);
while(Q->length())
{
int v=Q->dequeue();
cout<<v<<' ';//previsit
for(int w=G->first(v);w<G->n();w=G->next(v,w))
{
if(G->getMark(w)==UNVISITED)
{
G->setMark(w,VISITED);
Q->enqueue(w);
}
}
}
}
void Graphm::DFS(Graph* G,int v)
{
cout<<v<<' ';//previsit
G->setMark(v,VISITED);
for(int w=G->first(v);w<G->n();w=G->next(v,w))
{
if(G->getMark(w)==UNVISITED)
DFS(G,w);
}
}
void Graphm::print()
{
if(matrix==NULL)
{
cout<<"Empty graph\n";
return;
}
for(int i=0;i<numVertex;i++)
{
for(int j=0;j<numVertex;j++)
{
if(matrix[i][j]==INF) cout<<setw(5)<<"∞";
else cout<<setw(5)<<matrix[i][j];
}
cout<<endl;
}
}
}
4、Queue.h
5、AQueue.h
6、AQueue.cpp
参考队列的物理实现(顺序队列+链式队列)
7、main.cpp
#include <iostream>
using namespace std;
#define INF 1<<30
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
#include"Graphm.h"
#include"AQueue.h"
//#include"AQueue.cpp"
using namespace wangzhe;
int main(int argc, char** argv)
{
for(int i=1;i<=50;i++) cout<<'*';
cout<<"\n实验五:图的物理实现(邻接矩阵)\n";
for(int i=1;i<=50;i++) cout<<'*';
cout<<endl;
cout<<"请输入对应的数字实现相关操作:\n";
cout<<" 0、退出操作\n";
cout<<" 1、新建一个图\n";
cout<<" 2、输出当前图的邻接矩阵\n";
cout<<" 3、增添一条边\n";
cout<<" 4、删除一条边\n";
cout<<" 5、判断是否有某条边\n";
cout<<" 6、查询边权\n";
cout<<" 7、对当前图进行宽度优先遍历\n";
cout<<" 8、对当前图进行深度优先遍历\n";
cout<<" 9、输出边数\n";
cout<<"10、销毁当前图\n";
int order,vertex,edge;
int s,e,w;
Graphm G;
while(true)
{
cin>>order;
if(!order) break;
switch (order)
{
case 1:
{
cout<<"请分别输入图的顶点数和边数:\n";
cin>>vertex>>edge;
G.Init(vertex);
for(int i=1;i<=edge;i++)
{
cout<<"请依次输入第"<<i<<"条边的起点、终点和边权\n";
cin>>s>>e>>w;
if(!G.setEdge(s,e,w))
{
cout<<"请重新输入第"<<i<<"条边\n";
i--;continue;
}
G.setEdge(s,e,w);
}
cout<<"新建完成!\n";
break;
}
case 2:
{
cout<<"图的邻接矩阵为:\n";
G.print();
break;
}
case 3:
{
cout<<"请分别输入要增添边的起点、终点和边权:\n";
cin>>s>>e>>w;
while(!G.setEdge(s,e,w))
{
cout<<"请重新输入该条边\n";
cin>>s>>e>>w;
}
break;
}
case 4:
{
cout<<"请分别输入要删除边的起点和终点\n";
cin>>s>>e;
while(!G.delEdge(s,e))
{
cout<<"请重新输入该条边\n";
cin>>s>>e;
}
break;
}
case 5:
{
cout<<"请分别输入要判断边的起点和终点\n";
cin>>s>>e;
if(G.isEdge(s,e))
cout<<"该边存在\n";
else cout<<"该边不存在\n";
break;
}
case 6:
{
cout<<"请分别输入要查询边的起点和终点\n";
cin>>s>>e;
while(G.weight(s,e)==INF)
{
cout<<"请重新输入该条边\n";
cin>>s>>e;
}
cout<<G.weight(s,e)<<endl;
break;
}
case 7:
{
cout<<"请输入宽度优先遍历的起点\n";
cin>>s;
AQueue<int> QAQ(101);
G.BFS(&G,s,&QAQ);
cout<<endl;
G.memset();
break;
}
case 8:
{
cout<<"请输入深度优先遍历的起点\n";
cin>>s;
G.DFS(&G,s);
cout<<endl;
G.memset();
break;
}
case 9:
{
cout<<"当前边数为:"<<G.e()<<endl;
break;
}
case 10:
{
G.clear();
}
default:break;
}
}
return 0;
}