图的存储结构之邻接矩阵
邻接矩阵表示法
若有n个顶点,就是n*n的方阵,与边数无关
对称矩阵:从矩阵的左上角到右上角的主对角线为轴,右上角的元与左下角对应的元全都是相等的
有向图、无向图的邻接矩阵表示法
如:
无向图
总结:
- 无向图的邻接矩阵是对称的;
- 顶点i的度=第i行(列)中1的个数;
- 特别的:完全图的邻接矩阵中,对角元素为0,其余为1;
有向图
总结:
- 第i行含义:以结点vi为尾的弧(即出度边)
- 第i列含义:以结点vi为头的弧(即入度边)
- 有向图的邻接矩阵可能是不对称的
- 顶点的出度=第i行元素之和
- 顶点的入度=第i列元素之和
- 顶点的度=第i行元素之和+第i列元素之和
网的邻接矩阵表示法
定义为:
如:
存储表示
顶点表用一维数组存储、邻接矩阵用二维数组存储
用两个数组分别存储顶点表和邻接矩阵(也叫边表)
#define MaxInt 32767 //表示极大值,即无穷
#define MVNum 100 //最大顶点数
typedef char VerTexType; //设顶点的数据类型为字符型
typedef int ArcType; //假设边的权值类型为整形
typedef struct{
VerTexType vexs[MVNum]; //顶点表
ArcType arcs[MVNum][MVNum]; //邻接矩阵,可以看作边表
int vexnum,arcnum; //图的当前点数和边数
}AMGraph;//Adjacency Matrix Graph
采用邻接矩阵表示法创建无向网
已知一个图的点和边,使用邻接矩阵表示法来创建此图的方法比较简单,以无向网为例
【算法思想】
- 输入总顶点数和边数
- 依次输入点的信息存入顶点表中。
- 初始化邻接矩阵,使得每个权值初始化为极大值
- 构造邻接矩阵。
依次输入每条边依附的顶点和其权值
确定两个顶点在图中的位置之后,使相应边赋予相应的权值
同时使其对称边赋予相同的权值
补充一下顶点表:
【算法描述】
bool CreateUDN(AMGraph &G)
{
char v1,v2;
int w,i,j,k;
cin>>G.vexnum>>G.arcnum; //输入总顶点数,总边数
for(i=0;i<G.vexnum;i++)//依次输入点的信息
cin>>G.vexs[i];
for(i=0;i<G.vexnum;i++)
for(j=0;j<G.vexnum;j++)
G.arcs[i][j]=MAXInt;//初始化邻接矩阵,边的权值均置为极大值MAXInt
for(k=0;k<G.arcnum;k++){//构造邻接矩阵
cin>>v1>>v2>>w;//输入一条边所依附的顶点及边的权值
i=LocateVex(G,v1);
j=LocateVex(G,v2);//确定v1和v2在G中的位置,即顶点数组的下标
G.arcs[i][j]=w; //边<v1,v2>权值置为w
G.arcs[j][i]=G.arcs[i][j]; //边<v1,v2>的对称边<v2,v1>的权值为w
}//for
return true;
}//CreateUDN
注:从代码中可以得到,n个顶点和e条边的无向网图的创建,时间复杂度度为O(n+ n ^2 + e ), 其中对邻接矩阵G.arc的初始化耗费了O(n ^ 2)的时间。
【查找顶点的算法】
int LocateVex(AMGraph G,VertexType u){
//在图G中查找顶点u,存在则返回顶点表中的下标;否则返回-1
int i;
for(i=0;i<G.vexnum;i++)
if(u==G.vexs[i])
return i;
return -1;
}
建立无向网后,想要建立无向图,有向网和有向图时只需要稍稍改动即可
用代码实现无向网
#include<iostream>
using namespace std;
#define MaxInt 32767 //表示极大值,即无穷
#define MVNum 100 //最大顶点数
typedef char VerTexType; //设顶点的数据类型为字符型
typedef int ArcType; //假设边的权值类型为整形
typedef struct{
VerTexType vexs[MVNum]; //顶点表
ArcType arcs[MVNum][MVNum]; //邻接矩阵
int vexnum,arcnum; //图的当前点数和边数
}AMGraph;//Adjacency Matrix Graph
//在图中查找顶点
int LocateVex(AMGraph G,VerTexType u){
//在图G中查找顶点u,存在则返回顶点表中的下标;否则返回-1
int i;
for(i=0;i<G.vexnum;i++)
if(u==G.vexs[i])
return i;
return -1;
}
//采用邻接矩阵表示法,创建无向网G
bool CreateUDN(AMGraph &G)
{
char v1,v2;
int w,i,j,k;
cout<<"分别输入总顶点数、总边数:";
cin>>G.vexnum>>G.arcnum; //输入总顶点数,总边数
cout<<"输入点的信息:";
for(i=0;i<G.vexnum;i++)//依次输入点的信息
cin>>G.vexs[i];
for(i=0;i<G.vexnum;i++)
for(j=0;j<G.vexnum;j++)
G.arcs[i][j]=MaxInt;//初始化邻接矩阵,边的权值均置为极大值MAXInt
cout<<"请输入一条边所依附的两个顶点、权值:";
for(k=0;k<G.arcnum;k++){//构造邻接矩阵
cin>>v1>>v2>>w;//输入一条边所依附的顶点及边的权值
int i=LocateVex(G,v1);
int j=LocateVex(G,v2);//确定v1和v2在G中的位置,即顶点数组的下标
G.arcs[i][j]=w; //边<v1,v2>权值置为w
G.arcs[j][i]=G.arcs[i][j];
//边<v1,v2>的对称边<v2,v1>的权值为w
}//for
return true;
}//CreateUDN
int main()
{
AMGraph G;
CreateUDN(G);
cout<<"无向网为:";
for(int i=0;i<G.vexnum;i++)
{
for(int j=0;j<G.vexnum;j++){
cout<<G.arcs[i][j]<<" ";
}
cout<<endl;
}//for
return 0;
}
实现结果为:
优点:
- 直观、简洁,便于判断两个顶点是否有边。
- 便于计算各顶点的度
- 方便找任意顶点的邻接点
缺点:
- 不便于增加和删除顶点
- 浪费空间——存稀疏图(点多边少)有大量无效元素,空间复杂度为O(n^2),存稠密图还是很合算。
- 浪费时间——统计稀疏图中一共有多少条边,时间复杂度为O(n^2).