图的深度优先遍历DFS(邻接表实现)c语言

要实现该算法首先要知道邻接表的概念。

邻接表是一种常用的图的存储结构,它的结构特点是:

顶点由一个一维数组存储;

邻接点用链表存储

相比于单纯用数组实现的邻接矩阵,邻接表可以避免空间浪费

其图解如下:

《图的深度优先遍历DFS(邻接表实现)c语言》

firstedge指向边表第一个结点。

边表的adjvex的值代表与V0顶点有边的顶点下标,例:

A的firstedge指向边表的1而后指向2,3,意思是A与B,C,D各有一条共同的边。

算法的时间复杂度:对于n个顶点e条边的图,找邻接点所需的时间取决于顶点和边的数量,故为O(n+e)

邻接表结构代码实现如下:

/*邻接表结构*/
typedef char VertexType;     //顶点类型 
typedef int EdgeType;		//权值类型 

/*边表结点*/ 
typedef struct EdgeNode
{
	int adjvex;      	 	//邻接点域,保存邻接点下标    
	EdgeType weight;		//存储权值,非网图则不需要 
	struct EdgeNode *next;	//链域,指向下一个邻接点 
}EdgeNode;

typedef struct VertexNode
{
	VertexType data;       	//顶点域 
	EdegeNode *firstedge;	//边表头指针	
}VertexNode,AdList[MAX];

typedef struct
{
	AdjList adjList;
	int numVertexes,numEdges;    //顶点数量和边数量 
}GraphAdjList,*GraphAdj; 

创建邻接表:

/*邻接表创建*/
void create(GraphAdj G)
{
	int i,j,k;
	EdgeNode *e;
	printf("输入顶点数,边数:");
	scanf("%d%d",&G->numVertexes,&G->numEdges);
	for(i=0;i<G->numVertexes;i++)          //建立顶点表 
	{
		scanf("%c",&G->adjList[i].data);
		G->adjList[i].firstedge=NULL; 		//注意将边表置空 
	}
	for(k=0;k<G->numEdges;k++)             //建立边表 
	{
		printf("输入边(Vi,Vj)上的顶点序号:");
		scanf("%d%d",&i,&j);
		/*使用头插法加入边表结点*/
		e=(EdgeNode *)malloc(sizeof(EdgeNode));   //生成边表结点 
		
		e->adjvex=j;
		e->next=G->adjList[i].firstedge;
		G->adjList[i].firstedge=e;
		
		e=(EdgeNode *)malloc(sizeof(EdgeNode));   //生成边表结点 
		
		e->adjvex=i;
		e->next=G->adjList[j].firstedge;
		G->adjList[j].firstedge=e;
				
	} 
	 
 } 

邻接表的深度优先遍历

邻接表的深度优先遍历同邻接矩阵的深度优先遍历大同小异,都需要创建一个标志数组,数组存放bool类型成员TRUE,FALSE。 其中TRUE表示已经访问过。

不同点:在递归函数中需要声明一个EdgeNode *类型的变量p来进行边表的遍历,也就是在边表的链表中遍历邻接点。

实现代码如下:

/*邻接表的深度优先递归*/
void DFS(GraphAdj G,int i)
{
	EdgeNode *p;
	visited[i]=TRUE;         		//访问过了该顶点,标记为TRUE 
	printf("%c",G->adjList[i].data);
	p=G->adjList[i].firstedge;     //让p指向边表第一个结点 
	while(p)                      //在边表内遍历 
	{
		if(!visited[p->adjvex])    //对未访问的邻接顶点递归调用 
			DFS(G,p->adjvex);    
		p=p->next;
	}
 } 
 
 //邻接表的深度遍历操作
 
void DFSTraverse(GraphAdj G)
{
	int i;
	for(i=0;i<G->numVertexes;i++)
		visited[i]=FALSE;         //初始设置为未访问 
	for(i=0;i<G->numVertexes;i++)
		if(!visited[i])
			DFS(G,i);	//对未访问的顶点调用DFS,若是连通图只会执行一次 			
} 


完整代码:

#include<stdio.h>
#include<stdlib.h>
#define MAX 10
#define INIFINITY 65535
#define TRUE 1
#define FALSE 0
typedef int Boole;  //布尔类型 存储TRUE FALSE
Boole visited[MAX];    //访问标志数组 

//邻接表结点定义
typedef char VertexType;  //顶点数据类型	 
typedef int EdgeType;    //边上的权值类型 

typedef struct EdgeNode  //边表结点   存储边表信息 
{
	int adjvex;		    //邻接点域,存储该顶点对应的下标 
	EdgeType weight;	//权值 
	struct EdgeNode *next;	//链域,指向下一个邻接点 
}EdgeNode;

typedef struct VertexNode   //顶点表结点
{
	VertexType data;      //顶点域,存储顶点信息 
	EdgeNode *firstedge;	//边表头指针,指向此顶点的第一个邻接点 
}VertexNode,AdjList[MAX]; 


typedef struct
{
	AdjList adjList;     
	int numVertexes,numEdges;   //图中当前顶点数和边数 
}GraphAdjList,*GraphAdj;

 
/*邻接表创建*/
void create(GraphAdj G)
{
	int i,j,k;
	EdgeNode *e;
	printf("输入顶点数和边数:");
	scanf("%d%d",&G->numVertexes,&G->numEdges);
	for(i=0;i<G->numVertexes;i++)          //建立顶点表 
	{
		scanf("%c",&G->adjList[i].data);    //输入顶点的符号 
		G->adjList[i].firstedge=NULL; 		//将边表置空 
	}
	for(k=0;k<G->numEdges;k++)             //建立边表 
	{
		printf("输入边(Vi,Vj)上的顶点序号:");
		scanf("%d%d",&i,&j);
		/*使用头插法加入边表结点*/
		e=(EdgeNode *)malloc(sizeof(EdgeNode));   //生成结点 
		
		e->adjvex=j;
		e->next=G->adjList[i].firstedge;
		G->adjList[i].firstedge=e;
		
		e=(EdgeNode *)malloc(sizeof(EdgeNode));   //生成结点 
		
		e->adjvex=i;
		e->next=G->adjList[j].firstedge;
		G->adjList[j].firstedge=e;
				
	} 
} 


/*邻接表的深度优先递归*/
void DFS(GraphAdj G,int i)
{
	EdgeNode *p;
	visited[i]=TRUE;         		//访问过了该顶点,标记为TRUE 
	printf("%c",G->adjList[i].data);
	p=G->adjList[i].firstedge;     //让p指向边表第一个结点 
	while(p)                      //在边表内遍历 
	{
		if(!visited[p->adjvex])    //对未访问的邻接顶点递归调用 
			DFS(G,p->adjvex);    
		p=p->next;
	}
 } 
 
 //邻接表的深度遍历操作
 
void DFSTraverse(GraphAdj G)
{
	int i;
	for(i=0;i<G->numVertexes;i++)
		visited[i]=FALSE;       //初始设置为未访问 
	for(i=0;i<G->numVertexes;i++)
		if(!visited[i])       //对未访问的顶点调用DFS,若是连通图只会执行一次 
			DFS(G,i);				
} 

int main()
{
	GraphAdjList  G;
	create(&G);
	printf("\n");
	DFSTraverse(&G);
	printf("\n图遍历完毕");
	return 0;	 
 } 

错误警示:

一开始我在main函数中写的是

int main()
{
	GraphAdj G;
	create(G);
	printf("\n");
	DFSTraverse(G);
	printf("\n图遍历完毕");
	return 0;	 
 } 

可是运行时会出现问题,后来我才知道,GraphAdj G需要初始化,指针变量在分配了内存空间,即先要有指向之后才可以引用其值

但若是在cpp中可以把create函数的形参改成:

GraphAdj &G

&的意思是传进来节点指针的引用,括号内等价于 GraphAdj* &G,目的是让传递进来的指针发生改变

使用引用后,main函数就可以写成上述的形式了。

    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/qq_40663810/article/details/79292769
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞