- 查找函数(LocateVex查找坐标)
- 构建无向图(Undirected Graph)
- 输出邻接矩阵(print)
- 深度优先查找函数(DFS)
- 深度优先遍历(DFSTraverse)
图的遍历
- 深度优先遍历(DFS):类似于树中的先序遍历,整体思想是:先输出当前结点,在根据一定的次序去递归查找孩子。
- 广度优先遍历(BFS):类似于树中的层次遍历,需要用队列来体现结点访问的次序关系。
图的遍历需要考虑的问题
- 图是一种多对多的关系,每一个顶点有若干个度,结点之间也有若干条回路,每一个连通图都有若干种路径,那么我们怎么知道结点是否已经被访问过?
- 设置 "标志"数组 visited,数组每一位都对应一个结点的访问状态,0代表未被访问,1代表已访问。并且visited数组要设置成全局变量!
- 连通图与非连通图的问题
- 如果是连通图,根据程序递归,以任意一个端点为起点都可以走完整个图
- 如果是非连通图,存在“落单”的端点,“孤岛”端点,既无法一次走完整个图,此时就需要多次调用遍历函数来保证每一个结点都被访问到。
- 回到算法设计上而言,也就是解释了为什么会出现DFS、DFSTraverse两个函数,其实,如果是连通图由DFS函数就可以完成对整个图的遍历,DFSTraverse里面的
for(i=0;i<G->vexnum;i++)
(邻接矩阵第134-139行,邻接表第150-155行)就是为了非连通图而准备的。 - 由水流的例子,我们还可以知道:
深度优先遍历基本步骤
- 设置全局变量visited数组并初始化为全0,代表所有节点均未被访问
- 根据端点存放顺序:
- 2.1 选取初始端点:对初始端点进行访问,并在visited数值中标记成已访问状态(代码演示的初始端点是G->Vertex[i],此时i=0)
- 2.2 由初始端点开始对后续端点进行处理
(步骤2为深度优先搜索)
- 循环对所有节点都执行步骤2,前提是该节点未被访问!(对应函数DFSTraverse,主要用于非连通图能访问到每一个结点)
(步骤3 循环执行深度优先搜索,就是深度优先遍历)
完整源代码:
- 注:图的遍历算法在任何图与网中都适用,此处仅用无向图UDG进行演示!
- 注:邻接矩阵和邻接表对同一个图的深度优先遍历顺序是不一样的!因为此处邻接表的边关系是由头插法的形式插入,若采用尾插法则遍历序列与邻接矩阵一致
1.邻接矩阵的深度优先遍历
#include <stdio.h>
#include <stdlib.h>
#define VertexMax 100
typedef char VertexType;
typedef struct
{
VertexType Vertex[VertexMax];
int AdjMatrix[VertexMax][VertexMax];
int vexnum,arcnum;
}MGraph;
int LocateVex(MGraph *G,VertexType v)
{
int i;
for(i=0;i<G->vexnum;i++)
{
if(v==G->Vertex[i])
{
return i;
}
}
printf("No Such Vertex!\n");
return -1;
}
void CreateUDG(MGraph *G)
{
int i,j;
printf("输入顶点个数和边数:\n");
printf("顶点数 n=");
scanf("%d",&G->vexnum);
printf("边 数 e=");
scanf("%d",&G->arcnum);
printf("\n");
printf("\n");
printf("输入顶点元素(无需空格隔开):");
scanf("%s",G->Vertex);
printf("\n");
for(i=0;i<G->vexnum;i++)
for(j=0;j<G->vexnum;j++)
{
G->AdjMatrix[i][j]=0;
}
int n,m;
VertexType v1,v2;
printf("请输入边的信息:\n");
for(i=0;i<G->arcnum;i++)
{
scanf(" %c%c",&v1,&v2);
n=LocateVex(G,v1);
m=LocateVex(G,v2);
if(n==-1||m==-1)
{
printf("NO This Vertex!\n");
return;
}
G->AdjMatrix[n][m]=1;
G->AdjMatrix[m][n]=1;
}
}
void print(MGraph G)
{
int i,j;
printf("\n-------------------------------");
printf("\n 邻接矩阵:\n\n");
printf("\t ");
for(i=0;i<G.vexnum;i++)
printf(" %c",G.Vertex[i]);
printf("\n");
for(i=0;i<G.vexnum;i++)
{
printf("\t%c",G.Vertex[i]);
for(j=0;j<G.vexnum;j++)
{
printf(" %d",G.AdjMatrix[i][j]);
}
printf("\n");
}
}
int visited[VertexMax];
void DFS(MGraph *G,int i)
{
int j;
printf("%c",G->Vertex[i]);
visited[i]=1;
for(j=0;j<G->vexnum;j++)
{
if(G->AdjMatrix[i][j]==1&&visited[j]==0)
{
DFS(G,j);
}
}
}
void DFSTraverse(MGraph *G)
{
int i;
for(i=0;i<G->vexnum;i++)
{
visited[i]=0;
}
for(i=0;i<G->vexnum;i++)
{
if(visited[i]==0)
{
DFS(G,i);
}
}
}
int main()
{
MGraph G;
CreateUDG(&G);
print(G);
printf("\n\n深度优先遍历:");
DFSTraverse(&G);
return 0;
}
2.邻接表的深度优先遍历:
#include <stdio.h>
#include <stdlib.h>
#define VertexType char
#define VertexMax 20
typedef struct ArcNode
{
int adjvex;
struct ArcNode *next;
}ArcNode;
typedef struct VNode
{
VertexType vertex;
struct ArcNode *firstarc;
}VNode;
typedef struct
{
VNode AdjList[VertexMax];
int vexnum,arcnum;
}ALGraph;
int LocateVex(ALGraph *G,VertexType v)
{
int i;
for(i=0;i<G->vexnum;i++)
{
if(v==G->AdjList[i].vertex)
{
return i;
}
}
printf("No Such Vertex!\n");
return -1;
}
void CreateUDG(ALGraph *G)
{
int i,j;
printf("输入顶点个数和边数:\n");
printf("顶点数 n=");
scanf("%d",&G->vexnum);
printf("边 数 e=");
scanf("%d",&G->arcnum);
printf("\n");
printf("\n");
printf("输入顶点元素(无需空格隔开):");
for(i=0;i<G->vexnum;i++)
{
scanf(" %c",&G->AdjList[i].vertex);
G->AdjList[i].firstarc=NULL;
}
printf("\n");
int n,m;
VertexType v1,v2;
ArcNode *p1,*p2;
printf("请输入边的信息:\n\n");
for(i=0;i<G->arcnum;i++)
{
printf("输入第%d条边信息:",i+1);
scanf(" %c%c",&v1,&v2);
n=LocateVex(G,v1);
m=LocateVex(G,v2);
if(n==-1||m==-1)
{
printf("NO This Vertex!\n");
return;
}
p1=(ArcNode *)malloc(sizeof(ArcNode));
p1->adjvex=m;
p1->next=G->AdjList[n].firstarc;
G->AdjList[n].firstarc=p1;
p2=(ArcNode *)malloc(sizeof(ArcNode));
p2->adjvex=n;
p2->next=G->AdjList[m].firstarc;
G->AdjList[m].firstarc=p2;
}
}
void print(ALGraph G)
{
int i;
ArcNode *p;
printf("\n-------------------------------");
printf("\n图的邻接表表示:\n");
for(i=0;i<G.vexnum;i++)
{
printf("\n AdjList[%d]%4c",i,G.AdjList[i].vertex);
p=G.AdjList[i].firstarc;
while(p!=NULL)
{
printf("-->%d",p->adjvex);
p=p->next;
}
}
printf("\n");
}
int visited[VertexMax];
void DFS(ALGraph *G,int i)
{
int j;
struct ArcNode *p;
int w;
printf("%c",G->AdjList[i].vertex);
visited[i]=1;
p=G->AdjList[i].firstarc;
while(p!=NULL)
{
w=p->adjvex;
if(visited[w]==0)
{
DFS(G,w);
}
p=p->next;
}
}
void DFSTraverse(ALGraph *G)
{
int i;
for(i=0;i<G->vexnum;i++)
{
visited[i]=0;
}
for(i=0;i<G->vexnum;i++)
{
if(visited[i]==0)
{
DFS(G,i);
}
}
}
int main()
{
ALGraph G;
CreateUDG(&G);
print(G);
printf("\n\n深度优先遍历:");
DFSTraverse(&G);
return 0;
}
执行结果:
- 邻接矩阵
- 邻接表