自然界中有很多事物可以用图来表示其间的关系,在电脑中可以通过处理图来解决实际问题,但是问题来了,
如何将实际问题转化为图可以表示的形式?
如何在计算机中存储图,有几种方式?
如果图只是体现了节点与节点间是否有关系,那么如果节点本身的内容就很重要,怎么存储?
第一个问题-图的输入
要想在计算机中创建一个图的数据结构,就得先把现有的图输入进去,那么现有的图用现在的按行输入的方式怎么表示呢?
下面是POJ中2386题对图的表示,其中10和12为下面图的长和宽
10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.
除了用上面这中直接的表示,也可以将问题用画图的方式呈现在纸上,
然后得出有多少个节点,有多少条边,那些节点之间有联系,,这个联系是单向的还是双向的,这个联系有没有权重,如果有的话,每个节点之间的权重是多少,
知道上面这些问题后,就可以按照上面的这些关键信息,组织代码,确定先输入什么再输入什么,确定怎么输入才能完整的记录一个图。
图的第一种存储方式-邻接矩阵
邻接矩阵的表示
邻接矩阵就像一个坐标轴上存在的点和线,纵轴和横轴是一样的数据,即用来表示节点数据的数组,如果某个点和另一个点有关系,就从该点的纵轴引出一条线,从另一点所在的横轴引出一条线,在两条线的交点处做上标记或者写上权重,这样就可以用这个数据结构表示自然界的图了。
用邻接矩阵创建一个图
数据结构
用来存储节点数据的数组
(节点可以有多种类型)
(可以不止用数组存储,用其他数据结构也可,只要能保存完整的必须的节点数据)
存储图的节点数量和边的数量的变量
(在遍历时会用的到,用来确定遍历什么时候结束)
一个二维数组
(也就是邻接矩阵,用来表示节点与节点之间的关系,即是否相连,或如果相连的话,其间的权重是多少)
不同的输入方式
第一种
输入节点个数,边数
输入所有的节点(存入数组,必须要各不相同,否则会变复杂)
输入一个节点与另一个节点或者加上权重(表示两个节点相连,节点的先后也可以代表方向)
(这第三步要输入节点之间的关系或权重依旧需要遍历数组,找到节点的位置,以便在矩阵中定位)
第二种
输入节点个数,边数(有了节点个数其实就能创建一个空白的邻接矩阵了)
输入一个节点和另一个节点或者加上权重
循环知道所有关系输入完成
(问题:一个节点可能与多个节点相连,那么在输入该节点存入数组后,再次输入需要遍历一遍数组,以查看该节点是否已经存在,
如果不想遍历的话,就需要用一种不允许重复的数据结构存储节点数据,这种数据结构本身使用就是需要代价的)
第三种
输入一个节点和另一个节点或者加上权重
循环上面的过程直到输入停止条件结束
(节点个数和边数可以由上面的输入得知)
#可见在输入时做的工作越多越详细,代码越好写,越简单,而输入越接近图,没有自己的提取和总结的话,会比较麻烦,代码需要进行规范的地方越多
#不同的输入方式有不同的创建代码
第一种输入方式创建邻接矩阵
这里是第一种输入方式的图的创建代码(无向图带权重):
#include <iostream>
#define MAXNUM 100
using namespace std;
typedef char VexType;
typedef int ArcType;
typedef struct{
VexType vex[MAXNUM];
ArcType arc[MAXNUM][MAXNUM];
int point,line;
}AMGraph;
int CreateAM(AMGraph &G)
{
cin>>G.point>>G.line;//输入节点数和边数
for(int i =0;i<G.point;i++) //输入节点数据
{
cin>>G.vex[i];
}
for(int x =0;x<G.point;x++)
{
for(int y =0;y<G.point;y++)
{
G.arc[x][y]= -1; //初始化邻接矩阵
}
}
for(int k =0;k<G.line;k++)
{
VexType v1,v2;
int w;
cin>>v1>>v2>>w; //输入两个节点和权重
int p_x,p_y;
for(int q =0;q<G.point;q++) //找到节点在数组中的位置
{
if(G.vex[q] == v1)
p_x = q;
}
for(int r =0;r<G.point;r++)
{
if(G.vex[r] == v2)
p_y = r;
}
G.arc[p_x][p_y] =w;
G.arc[p_y][p_x]= G.arc[p_x][p_y]; //无向图是对称的
}
}
int main()
{
AMGraph g;
CreateAM(g);
}
上面的代码是针对无向图带权重的
将权重设置为1即可表示无向图
修改对称就可以表示有向图带权重
将权重设置为1并修改对称就可以表示有向图不带权重
# 修改typedef后的数据类型就可以存储不同类型的节点数据
如果是第二种输入方式,就要边输入边创建数组,边判断数组中是否已经存在该节点,还要同时在邻接矩阵中设置好权重或者节点之间的关系,由于有节点个数和边数还是比较方便的。
邻接矩阵的特点
可以扩展存储节点数据的数据结构,使之可以完整的存储节点数据
适合稠密图,如果是稀疏图的话,对于一个大的邻接矩阵可能会有很多没用的遍历,也会浪费较多的空间
如果是稀疏图,无向图的话,可以压缩存储,因为无向图是对称的
增加或者删除节点不方便,要修改整个数组和邻接矩阵
很容易判断两个节点是否相连以及其权重,因为二维数组只要知道位置可以随机访问
计算各个节点的度也很方便,计算每行或者每列的总和即可
边数可以在一开始输入,但是创建完邻接矩阵后,却不容易从该邻接矩阵判断出边数是多少,得整个遍历