深度优先遍历(Depth_First_Search),也称为深度优先搜索,简称DFS
深度优先遍历其实就是一个递归的过程,就像一个树的前序遍历。
连通图:
它从一个图中某个顶点V出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和V有路径相通的顶点都被访问到。
对于非连通图:
只需要对他的连通分量分别进行深度优先遍历,即在先前一个顶点进行一次深度优先遍历后,若图中还有顶点没有被访问,则另选图中未被访问的顶点作为起始点,重复上述过程,直到图中所有顶点都被访问了为止。
引用课件图片,便于理解:
#include<stdio.h>
#include<stdlib.h>
#define INFINITY 65535 //最大值∞ 会在带权的图中用到,即网
#define MAX_VERTEX_NUM 20 //图的最大顶点数
#define MAX_INFO 20 //最大信息数
#define MAX 999
typedef char InfoType; //附加信息类型
typedef int VRType; //顶点关系类型
typedef int VertexType; //顶点数据类型
typedef enum {DG, DN, UDG, UDN} GraphKind; //{有向图,有向网,无向图,无向网}
typedef int Boolean; //Boolean是布尔类型,其值是TRUE 或 FALSE
Boolean visited[MAX]; //访问标志的数组
//-----------------------数组表示法-----------------------//
typedef struct ArcCell {
VRType adj; //顶点关系类型,对无权图用1或0表示是否相邻;对带权图,则为权值类型
InfoType *info; //附加信息指针
} ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct {
VertexType vexs[MAX_VERTEX_NUM];//顶点向量
AdjMatrix arcs; //邻接矩阵
int vexnum, arcnum; //当前顶点数和弧数
GraphKind kind; //图的种类
}MGraph;
//-----------------------图的邻接表存储-----------------------//
//弧的节点结构
typedef struct ArcNode{
int adjvex; //该弧所指向的顶点位置
struct ArcNode *nextarc;//指向下一条弧的指针
InfoType *info; //当前结点(弧)的信息
}ArcNode;
//顶点的结点结构
typedef struct VNode{
VertexType data;//顶点信息
ArcNode *firstarc;//指向第一个依附于该顶点弧的指针
}VNode,*AdjList[MAX_VERTEX_NUM];
typedef struct {
AdjList vertices;
int vexnum,arcnum;//图的当前顶点数和弧数
int kind; //图的种类标志
}ALGraph;
//-----------------------对邻接矩阵进行深度优先遍历-----------------------//
void VisitFunc(int v)
{
printf("%d",v);
}
int FirstAdjVex(MGraph G, int v) { //返回v(序号)的第一个相邻节点(序号)
if(v > G.vexnum || v < 0)
return -1;
int j = 0; //如果是网
if(G.kind == DN || G.kind == UDN){
j = INFINITY;
}
for(int i = 0; i < G.vexnum; i++){
if(G.arcs[v][i].adj != j){
return i;
}
}
return -1;
}
int NextAdjVex(MGraph G, int v, int w) { //w是v的相邻节点,返回v相对w的下一个节点的序号,否则返回-1
int i, j;
j = 0; //如果为网
if (G.kind == DN || G.kind == UDN)
j = INFINITY;
//两顶点不相邻
if (G.arcs[v][w].adj == j)
return -1;
//从w之后的结点开始
for (i = w + 1; i < G.vexnum; i++)
if (G.arcs[v][i].adj != j)
return i;
return -1;
}
void DFS(MGraph G, int v) { //从第v个顶点出发递归地深度优先遍历图G
visited[v] = 1;
VisitFunc(G.vexs[v]); //访问第v个顶点
for (int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)){
if (!visited[w]){ //对未访问的邻接顶点w递归调用DFS
DFS(G, w);
}
}
}
void DFSTraverse(MGraph G) { //对图G做深度优先遍历
for (int i = 0; i < G.vexnum; ++i) {
visited[i] = 0; //访问标志数组初始化
}
for (int j = 0; j < G.vexnum; ++j) {
if (!visited[j])
DFS(G, j); //对未访问的顶点调用DFS
}
}
//邻接表为存储结构的图进行深度优先遍历
void DFSAL(ALGraph *G,int i) //以Vi为出发点对邻接表存储的图G进行DFS搜索
{
ArcNode *p;
VisitFunc(G->vertices[i]->data);
visited[i] = true; //标记Vi已访问
p = G->vertices[i]->firstarc; //取Vi边表的头指针
while(p) //依次搜索Vi的临界点Vj,j=p->adjvex
{
if(!visited[p->adjvex])
{
DFSAL(G,p->adjvex);
p=p->nextarc; //找Vi的下一个邻接点
}
}
}
void DFSTraverse(ALGraph *G) { //对图G做深度优先遍历
for (int i = 0; i < G->vexnum; ++i) {
visited[i] = 0; //访问标志数组初始化
}
for (int j = 0; j < G->vexnum; ++j) {
if (!visited[j])
DFSAL(G, j); //对未访问的顶点调用DFS
}
}
//建立图的邻接表结构
void CreateALGraph(ALGraph *G)
{
ArcNode *e;
printf("请输入顶点数和边数:\n");
scanf("%d,%d",&G->vexnum,&G->arcnum); //输入顶点数和边数
for(int i=0;i<G->vexnum;i++)
{
scanf("%d",&G->vertices[i]->data); //输入顶点信息
G->vertices[i]->firstarc = NULL; //将边表置为空表
}
for(int k=0;k<G->arcnum;k++)
{
int i,j;
printf("输入边(vi,vj)上的顶点序号:\n");
scanf("%d,%d",&i,&j); //输入边(vi,vj)上的顶点序号
e = (ArcNode*)malloc(sizeof(ArcNode)); //向内存申请空间,生成边表结点
e->adjvex = j; //邻接序号为j
e->nextarc = G->vertices[i]->firstarc=e; //将e指针指向当前顶点指向的结点
G->vertices[i]->firstarc = e; //将当前顶点的指针指向e
e = (ArcNode*)malloc(sizeof(ArcNode)); //向内存申请空间,生成边表节点
e->adjvex =i; //邻接序号为i
e->nextarc = G->vertices[j]->firstarc; //将e指针指向当前顶点指向的结点
G->vertices[j]->firstarc =e; //将当前顶点的指针指向e
}
}
int main() {
ALGraph *G;
G=(ALGraph*)malloc(sizeof(ALGraph));
CreateALGraph(G);
DFSTraverse(G);
return 0;
}