一、图的定义
图是一种比线性表更复杂的数据结构。G由两个集合V和E组成,记为G=(V,E),其中V是顶点的由穷非空集合,E是V中
顶点偶对的又穷集合,这些顶点偶对成为边。V(G)和E(G)通常分别表示图G的顶点集合和边集合,E(G)可以为空集。若E(G)为空,则图G只有顶点而没有边。
对于图G,若边集E(G)为有向边的集合,则称该图为有向图;若边集E(G)为无向边的集合,则称改图为无向图。
有向图边记作<x,y>,是有序的,与<y,x>方向不同。而无向图(x,y)与(y,x)相同,为同一条边。
二、图的存储结构
1、邻接矩阵表示法
邻接矩阵是表示顶点之间关系的矩阵。设G(V,E)是具有n个顶点的图,则G的邻接矩阵是具有如下性质的n阶方阵。
例如,对于一中所示图:
代码如下:
#define MaxInt 32767
#define MVNum 100
typedef char VerTexType;
typedef int ArcType;
typedef struct
{
VerTexType vexs[MVNum];
ArcType arcs[MVNum][NVNum];
int vexnum,arcnum;
}AMGraph;
创建无向网G代码如下:
Status createUDN(AMGraph &G)
{
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.arxs[i][j]=MaxInt;
for(k=0;k<G.arcnum;k++)
{
cin>>v1>>v2>>w;
i=LocateVex(G,v1);
j=LocateVex(G,v2);
G.arcs[i][j]=w;
G.arcs[i][j]=G.arcs[i][j];
}
return OK;
}
(1)优点
①便于判断两个顶点之间是否边。
②便于计算各个顶点的度。
(2)缺点
①不便于增加和删除顶点。
②不便于统计边的数目。
③空间复杂度较高。
2、邻接表表示法
G1的邻接表
G2的邻接表
代码如下:
#define MVNum 100
typedef struct ArcNode
{
int adjvex;
struct ArcNode *nextarc;
OtherInfo info;
}ArcNode;
typedef struct VNode
{
VerTexType data;
ArcNode *firstarc;
}VNode,AdjList[MVNum];
typedef struct
{
AdjList vertices;
int vexnum,arcnum;
}ALGraph;
创建无向图代码如下:
Status createUDG(AMGraph &G)
{
cin>>G.vexnum>>G.arcnum;
for(i=0;i<G.vexnum;i++)
{
cin>>G.vertices[i].data;
G.vertices[i].firstarc=NULL;
}
for(k=0;k<G.arcnum;k++)
{
p1=new ArcNode;
p1->adjvex=j;
p1->nextarc=G.vertices[i].firstaerc;
G.vertices[j].firstarc=p2;
}
return OK;
}
三、图的遍历——DFS&BFS
1、深度优先搜索(DFS)
(1)从图中某个顶点v出发,访问v;
(2)找出刚访问过的顶点的第一个未被访问的邻接点,访问该顶点。以该顶点为新顶点,重复此步骤,直至刚访问过的顶点没有为未访问的邻接点为止。
(3)返回前一个访问过的且仍有未被访问的邻接点的顶点,找出该顶点的下一个未被访问的邻接点,访问该顶点。
(4)重复(2)(3),直至图中所有顶点都未被访问过,搜索结束。
例如下图:
DFS访问下去,即为:
v1→v2→v4→v8→v5→v3→v6→v7
连通图的遍历代码:
bool visited[MVNum];
void DFS(Graph G,int v)
{
cout<<v;
visited[v]=true;
for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w))
if(!visited[w])
DFS(G,w);
}
非连通图采用邻接矩阵的DFS代码如下:
void FDS_AM(ALGraph G,int v)
{
cout<<v;
visited[v]=ture;
for(w=0;w<G.vexnum;w++)
if((G.arcs[v][w]!=0)&&(!visited[w]))
DFS_AM(G,w);
}
非连通图采用邻接表的DFS代码如下:
void FDS_AL(ALGraph G,int v)
{
cout<<v;
visited[v]=ture;
p=G.vertices[v],firstarc;
while(p!=NULL)
{
w=p->adjvex;
if(!visited[w])
DFS_AL(G,w);
p=p->nextarc;
}
}
2、广度优先搜索(BFS)
(1)从图中某个顶点v出发,访问v。
(2)依次访问v的各个未曾访问的邻接点。
(3)分别从这些邻接点出发依此访问它们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问。重复步骤(3),直至图中所有已被访问的顶点的邻接点都被访问到。
按照BFS访问顺序为:
v1→v2→v3→v4→v5→v6→v7→v8
连通图遍历代码如下:
void BFS(Graph G,int v)
{
cout<<v;
visited[v]=true;
InitQueue(Q);
EnQueue(Q,v);
while(!QueueEmpty(Q))
{
DeQueue(Q,u);
for(w=FirstAdjVex(G,u);W>=0;w=NextAdjVex(G,u,w))
if(!visited[w])
{
cout<<w;
visited[w]=true;
EnQueue(Q,w);
}
}
}