一、图是什么?
图通常以一个2元组G=<V,E>表示,V表示节点集,E表示边集,|V|表示节点集中元素的个数及节点数,也被称作图的阶,例如在N阶图中有N个节点。|E|表示边集中元素的个数及边数。
若图G中每条边都是没有方向的则称之为无向图,若图G中的每条边都是有方向的则称之为有向图,在无向图中每条边都是有2各节点组成的无序对,例如节点V1和节点V3之间的边记作(v1,v3)或(v3,v1)。在有向图中有向边也被称为弧,每条弧都是有2个节点组成的有序对,例如从节点V1到节点V3的弧记为<v1,v3>,v1被称之为弧尾V3被称为弧头如下图所示,结点的度数与及该节点相关联的边数记作TD(v).
二、图的存储
图的结构比较复杂,任何2个节点之间都可能有关系,图的存储分为顺序存储和链式存储,顺序存储包括邻接矩阵和边集数组,链式存储包括邻接表,链式向前星,十字链表和邻接多重表。
1.邻接矩阵
邻接矩阵通常采用1个1维数组存储图中节点的信息采用1个2维数组存储图中节点之间的邻接关系。
1. 邻接矩阵的表示方法
(1)无向图的邻接矩阵
在无向图中若从节点为vi到节点vj有边,则邻接矩阵M[i][j]=M[j][i]=1,否则M[i][j]=0.
无向图邻接矩阵的特点如下
1 无向图的邻接矩阵是对称矩阵,并且是唯一的.
2 第i行或第i列非0元素的个数正好是第i个结点的度,上图中的邻接矩阵第3列非0元素的个数为2说明第3个节点C的度数为2.
(2)有向图的连接矩阵
在有向图中若从节点为vi到节点vj有边,则邻接矩阵M[i][j]=1,否则M[i][j]=0.
(3)网的邻接矩阵
M[i][j]=w(ij)||无穷大;
2.邻接矩阵的数据结构定义
# define MAXVnum 100
typedef struct{
char vex[MAXVnum];
int edge[MAXVnum][MAXVnum];
int vexnum,edgenum;
}AMGraph;
void CreateAMGraph(AMGraph &G){
int i,j;
VexType u,v;
cout<<"请输入节点数“<<endl;
cin>>G.vexnum;
cout<<"请输入边数<<endl;
cin>>G.edgenum;
cout<<"请输入节点信细<<;
for(i=0;i<G.vexnum;i++){
cin>>G.vex[i];
}
for(i=0; i<G.vexnum;i++){
for(j=0;j<G.vexnum;j++){
G.Edge[i][j]=0;
}
}
cout<<"请输入每条边依附的两个节点”<<endl;
while(G.degenum--){
cin>>u>>v;
i=locatevex(u);
j=locatevex(v);
G.Edge[i][j]=G.Edge[j][i]=1;
}
}
2.邻接表(邻接链表)
1.邻接表的表示方法
邻接表是图的一种链式的存储方式其数据结构包括2部分节点和邻接点,
2.邻接表的数据结构定义
typedef struct VexNode{
VexType data;
AdjNode *first;
}VexNode;
typedef struct AdjNode{
int v;
struct AdjNode *next;
}AdjNode;
typedef struct{
VexNode Vex[MAX];
int vexnum,edgenum;
}ALGraph;
void GreateALGraph(AlGraph &G){
char u,v;
cout<<"请输入定点属于边数"<<endl;
cin>>G.vexnum>>G.edgenum;
cout<<"请输入节点信息"<<endl;
for(i=1;i<=G.vexnum;i++){
cin>>G.vex[i].data;
G.vex[i].first=NULL;
}
cout<<"请输入每条边的两个顶点"<<endl;
while(G.edgenum--){
cin>>u>>v;
int i=locate(u);
int j=locate(v);
AdjNode *s;
s=new AdjNode;
s->v=j;
s->next=G.vex[i].first;
G.vex[i].first=s;
}
}
2链式向前星
数据结构定义
struct node{
int to,next,w;
}edge[MAXE];
int head[MAX];
int cnt=0;
void add(int u,v,w)
{
edge[cnt].to=v;
edge[cut].next=head[u];
head[u]=cut++;
}
for(i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].next;
inw w=edge[i].w;
}
练习1
给定有N个节点M条边的有向图对每个结点V都求A(v),表示从节点V出发能到达的编号的最大的节点. NBA
输入第一行包含2个整数N,M接下来的大M行每行都包括2个整数UV,表示边UV,节点的编号为1到N。
输入样例
4 3
1 2
2 4
4 3
输出样例
4 4 3 4
二、图的遍历
1 广度优先遍历
代码实现
void BFS(AMGraph G,int v){
int u,v;
queue<int>q;
cout<<G.vex[v];
visited[v]=true;
q.push(v);
while(!q.empty()){
u=q.front();
q.pop();
for(i=0;i<G.vexnum;i++){
if(G.edge[u][i]&&visited[i]){
cout<<G.vex[i];
visited[i]=true;
q.push(i);
}
}
}
}
void BFS(AMGraph G,int v){
int u,v;
AdjNode *p;
queue<int>q;
cout<<G.vex[v];
visited[v]=true;
q.push(v);
while(!q.empty()){
u=q.front();
q.pop();
p=G.vex[u].first;
while(p!=NULL){
w=p->v;
if(!visitd[w]){
cout<<G.vex[w].data;
visited[w]=true;
q.push(w);
}
p=p->next;
}
}
}