图与图的遍历

本文详细介绍了图的定义、类型、存储结构,并重点讲解了图的深度优先遍历(DFS)和广度优先遍历(BFS)算法,包括邻接矩阵和邻接表两种存储方式的实现。深度优先遍历适合目标明确的情况,而广度优先遍历适用于寻找最优解。
摘要由CSDN通过智能技术生成

图与图的遍历

本文参考自《大话数据结构》

定义

图(graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。

图定义

注意

  • 在图中数据元素,我们则称之为顶点(Vertex);
  • 在图结构中,不允许没有顶点;
  • 在图中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边集可以是空的;

各种图定义

无向边 :若顶点vi到vj之间的边没有方向,则称这条边为无向边(Edge),用无序偶对(vi,vj)表示。如果图中任意两个顶点之间的边都是无向边,则称该图为无向图;

有向边 :若从顶点vi到vj的边有方向,则称这条边为有向边,也称为弧(Arc),用有序偶对<vi,vj>来表示,vi称为弧尾(Tail),vj称为弧头(Head)。如果途中任意两个顶点之间的边都是有向边,则称该图为有向图。

有向图和无向图定义

无向边用()表示,而有向边用<>表示;

在图中,若不存在顶点到其自身的边,且同一条边不重复出现,则称这样的图为简单图;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AFotjgxu-1605454325635)(pic/简单图定义.png)]

在无向图中,如果任意两个顶点之间都存在边,则称该图为无向完全图。含有n个顶点的无向完全图有n*(n-1)/2条边。

无向完全图

在有向图中,如果任意两个顶点之间都存在方向互为相反的两条弧,则称该图为有向完全图。含有n个顶点的有向完全图有n*(n-1)条边。

有向完全图

结论:对于具有n个顶点和e条边数的图,无向图0<=e<=n*(n-1)/2,有向图0<=e<=n*(n-1)

有很少条边或弧的图称为稀疏图,反之称为稠密图(稀疏和稠密是相对而言的)。

有些图的边或弧具有与它相关的数字,这种与图的边或弧相关的数字叫做权(Weight)。这些权可以表示从一个顶点到另一个顶点的距离或耗费。这种带权的图通常称为网。

网定义

假设有两个图G=(V,{E})G'=(V',{E'}),如果V'∈VE'∈E,则称G’为G的子图

子图定义

对于无向图边数=各顶点度数和的一半

对于有向图边数=各顶点出度和=各顶点入度和

树中根结点到任意结点的路径是唯一的,但是图中顶点和顶点之间的路径却不是唯一的。

路径的长度是路径上的边或弧的数目。

第一个顶点到最后一个顶点相同的路径称为回路或环。序列中定点不重复出现的路径称为简单路径。除了第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路称为简单回路或简单环。

连通图相关术语

在无向图G中,如果从顶点v到顶点v’有路径,则称v和v’是连通的。如果对于图中任意两个顶点vi,vj∈E,vi和vj都是连通的,则称G是连通图。

无向图中的极大连通子图称为连通分量。注意连通分量的概念,它强调:

  • 要是子图;
  • 子图要是连通的;
  • 连通子图含有极大顶点数;
  • 具有极大顶点数的连通子图包含依附于这些顶点的所有边

在有向图G中,如果对于每一对vi,vj∈V,vi≠vj,从vi到vj和vj到vi都存在路径,则称G是强连通图。有向图中的极大强连通子图称做有向图的强连通分量

一个连通图的生成树是一个极小的连通子图,它含有图中全部的n个顶点,但只有足以构成一棵树的n-1条边

如果一个有向图恰有一个顶点入度为0,其余顶点的入度均为1,则是一棵有向树。一个有向图的生成森林由若干棵有向树组成,含有图中全部顶点,但只有足以构成若干棵不相交的有向树的弧。

抽象数据类型

ADT 图(Graph)
Data
	顶点的有穷非空集合和边的集合
Operation
	CreateGraph(*G, V, VR):按照顶点集V和边弧集VR的定义构造图G
	DestoryGraph(*G):图G存在则销毁
	LocateVex(G,u):若图G中存在顶点u,则返回图中的位置
	GetVex(G,v):返回图G中顶点v的值
	PutVex(G,v,value):将图G中顶点v赋值value
	FirstAdjVex(G,*v):返回顶点v的一个邻接顶点,若顶点在G中无邻接顶点返回空
	NextAdjVex(G,v,*w):返回顶点v相对于顶点w的下一个邻接顶点,若w是v的最后一个邻接点则返回"空"
	InsertVex(*G,v):在图G中增添新顶点v
	DeleteVex(*G,v):删除图G中顶点v及其相关的弧
	InsertArc(*G,v,w):在图G中增添弧<v,w>,若G是无向图,还需要增添对称弧<w,v>
	DeleteArc(*G,v,w):在图G中,删除弧<v,w>,若G是无向图,则还删除对称弧<w,v>
	DFSTraverse(G):对图G中进行深度优先遍历,在遍历过程对每个顶点调用
	BFSTraverse(G):对图G中进行广度优先遍历,在遍历过程对每个顶点调用
endADT

存储结构

邻接矩阵

图的邻接矩阵存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(称为邻接矩阵)存储图中的边或弧的信息。

有向图带权邻接矩阵

无向图邻接矩阵也是一个对称矩阵

有了这个矩阵,我们就可以很容易地知道图中的信息:

  1. 我们要判定任意两顶点是否有边无边就非常容易了;
  2. 我们要知道某个顶点的度,其实就是这个顶点vi在邻接矩阵中第i行(或第i列)的元素之和;
  3. 求顶点vi的所有邻接点就是将矩阵中第i行元素扫描一遍,arc[i][j]为1就是邻接点;
typedef char VertexType;	//顶点类型由用户定义
typedef int EdgeType;	//边上的权值类型由用户定义
#define MAXVEX 100	//最大顶点数,由用户定义
#define INFINITY 65535	//代表无穷大
struct MGraph{
	VertexType vexs[MAXVEX];	//顶点表
	EdgeType arc[MAXVEX][MAXVEX];	//邻接矩阵,可看作边表
	int numVertexes, numEdges;	//图中当前的顶点数和边数
};
/*建立无向网的邻接矩阵表示*/
void CreateMGraph(MGraph* G){
	int i, j, k, w;
	printf("输入顶点数和边数:\n");
	scanf("%d,%d",&G->numVextexes, &G->numEdges);	//输入顶点数和边数
	for(i=0;i<G->numVertexes;i++)	//读入顶点信息,建立顶点表
		scanf(&G->vexs[i]);
	for(i=0;i<G->numVertexes;i++)
		for(j=0;j<G->numVertexes;j++)
			G->arc[i][j] = INFINITY;		//邻接矩阵初始化
	for(k=0;k<G->numEdges;k++){	//读入numEdges条边,建立邻接矩阵
		printf("输入边(vi,vj)上的下标i,下标j和权w:\n);
		scanf("%d,%d,%d",&i,&j,&w);	//输入边(vi,vj)上的权w
		G->arc[i][j] = w;
		G->arc[j][i] = G->arc[i][j];	//因为是无向图,矩阵对称
	}
}

从代码可以看出,n个顶点和e条边的无向网图的创建,时间复杂度为O(n+n^2+e),其中对邻接矩阵Garc的初始化耗费了O(n^2)的时间。

邻接表

对于边数相对顶点数较少的图,用邻接矩阵存储边会造成很大的内存空间浪费,所以这里考虑另外一种存储结构:邻接表。

  1. 图中顶点用一个一维数组存储,当然,顶点也可以用单链表来存储,不过数组可以较容易地读取顶点信息,更加方便。另外,对于顶点数组中,每个数据元素还需要存储指向第一个邻接点的指针,以便于查找该顶点的边信息。
  2. 图中每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以用单链表存储,无向图称为顶点vi的边表,有向图则称为顶点vi作为弧尾的出边表。

有向图带权邻接表

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[MAXVEX];

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

无向图邻接表创建

/* 建立图的邻接表结构 */
void CreateALGraph(GraphAdjList* G){
	int i, j, k;
	EdgeNode* e;
	printf("输入顶点数和边数:\n");
	scanf("%d,%d", &G->numVertexes, &G->numEdges);	//输入顶点数和边数
	for(i=0;i<G->numVertexes;i++){
		scanf(&G->adjList[i].data);	//输入顶点信息
		G->adjList[i].firstedge = NULL;	//将边表置为空表
	}
	for(k=0;k<G->numEdges;k++){	//建立边表
		printf("输入边(vi,vj)上的顶点序号:\n");
		scanf("%d,%d",&i,&j);
		e = (EdgeNode*)malloc(sizeof(EdgeNode));	//向内存申请空间,生成边表结点
		e->adjvex = j;		//邻接序号为j
		e->next = G->adjList[i].firstedge;		//将e指针指向当前顶点指向的结点
		G->adjList[i].firstedge = e;	//将当前顶点的指针指向e
		e = (EdgeNode*)malloc(sizeof(EdgeNode));	//向内存申请空间,生成边表结点
		e->adjvex = i;		//邻接序号为i
		e->next = G->adjList[j].firstedge;		//将e指针指向当前顶点指向的结点
		G->adjList[j].firstedge = e;	//将当前顶点的指针指向e
	}
}

算法的时间复杂度:对于n个顶点e条边来说,很容易得出是O(n+e)

十字链表,邻接多重表,边集数组的相关介绍本文没有介绍,可以查查网上其他资料。

图的遍历

定义

从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次,这一过程就叫做图的遍历。

深度优先遍历

深度优先搜索图

深度优先遍历,简称DFS。

typedef int Boolean;
Boolean visited[MAX];
/* 邻接矩阵的深度优先递归算法 */
void DFS(MGraph G, int i){
	int j;
	visited[i] = TRUE;
	printf("%c",G.vexs[i]);		//打印结点,也可以是其他操作
	for(j=0;j<G.numVertexes;j++)
		if(G.arc[i][j] == 1 && !visited[j])
			DFS(G, j);		//对未访问的邻接点递归调用
}

/* 邻接矩阵的深度遍历 */
void DFSTraverse(MGraph 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);
}
/* 邻接表的深度优先递归算法 */
void DFS(GraphAdjList GL, int i){
	EdgeNode* p;
	visited[i] = TRUE;
	printf("%c",GL->adjList[i].data);
	p = GL->adjList[i].firstedge;
	while(p){
		if(!visited[p->adjvex])
			DFS(GL, p->adjvex);
		p = p->next;
	}
}

/* 邻接表的深度遍历操作 */
void DFSTraverse(GraphAdjList GL){
	int i;
	for(i = 0;i < GL->numVertexes;i++)
		visited[i] = FALSE;		//初始化所有顶点状态都是未访问状态
	for(i=0;i<GL->numVertexes;i++)
		if(!visited[i])
			DFS(GL, i);
}

对比两个不同数据结构的深度优先遍历算法,对于n个顶点e条边的图来说,邻接矩阵由于是二维数组,要查找每个顶点的邻接点需要访问矩阵中的所有元素,因此都需要O(n^2)的时间。而邻接表作存储结构时,找邻接点所需的时间取决于顶点和边的数量,所以是O(n+e)。显然对于点多边少的稀疏图来说,邻接表结构使得算法在时间效率上大大提高。

广度优先遍历

广度优先搜索图

广度优先遍历,简称BFS。

邻接矩阵结构的广度优先遍历算法

/* 邻接矩阵的广度遍历算法 */
void BFSTraverse(MGraph G){
	int i, j;
	Queue q;
	for(i=0;i<G.numVertexes;i++)
		visited[i] = FALSE;	
	InitQueue(&Q);	//初始化一辅助用的队列
	for(i=0;i<G.numVertexes;i++){	//对每一个顶点做循环
		if(!visited[i]){	//未访问过的
			visited[i] = TRUE;		//设置当前顶点访问过
			printf("%c",G.vexs[i]);	//打印顶点,也可以其他操作
			EnQueue(&Q, i);	//将此顶点入队
			while(!QueueEmpty(Q)){	//若当前队列不为空
				DeQueue(&Q, &i);	//将队中元素出队列,赋值给i
				for(j=0;j<G.numVertexes;j++)
					//判断其他顶点若与当前顶点存在边且未被访问过
					if(G.arc[i][j] == 1 && !visited[j]){
						visited[j] = TRUE;	//将找到的此顶点标记为已访问
						printf("%c", G.vexs[j]);	//打印顶点
						EnQueue(&Q, j);		//将找到的此顶点入队
				}
			}
		}
	}
}
/* 邻接表的广度遍历算法 */
void BFSTraverse(GraphAdjList GL){
	int i;
	EdgeNode* p;
	Queue q;
	for(i=0;i<GL->numVertexes;i++)
		visited[i] = FALSE;	
	InitQueue(&Q);	//初始化一辅助用的队列
	for(i=0;i<GL->numVertexes;i++){	//对每一个顶点做循环
		if(!visited[i]){	//未访问过的
			visited[i] = TRUE;		//设置当前顶点访问过
			printf("%c",GL->adjList[i].data);	//打印顶点,也可以其他操作
			EnQueue(&Q, i);	//将此顶点入队
			while(!QueueEmpty(Q)){	//若当前队列不为空
				p = GL->adjList[i].firstedge;	//找到当前顶点边表链表头指针
				while(p)
					//判断其他顶点若与当前顶点存在边且未被访问过
					if(!visited[p->adjvex]){
						visited[p->adjvex] = TRUE;	//将找到的此顶点标记为已访问
						printf("%c", GL->adjList[p->adjvex].data);	//打印顶点
						EnQueue(&Q, p->adjvex);		//将找到的此顶点入队
				}
				p = p->next;	//指针指向下一个邻接点
			}
		}
	}
}

广度和深度遍历算法没有优劣之分,不过如果图顶点和边非常多,不能在短时间内遍历完成,遍历的目的是为了寻找合适的顶点,那么选择哪种遍历就要仔细斟酌了。深度优先更适合目标比较明确,以找到目标为主要目的的情况,而广度优先更适合在不断扩大遍历范围时找到相对最优解的情况。

例子

图遍历例子

邻接矩阵实现
#include <stdio.h>
#include <stdlib.h>

typedef char VertexType;	//顶点类型
typedef int EdgeType;	//边上的权值类型
#define MAXVEX 100	//最大顶点数 
#define INFINITY 65535	//代表无穷大
bool visited[MAXVEX];	//标记结点是否遍历过 

struct MGraph{
	VertexType vexs[MAXVEX];	//顶点表
	EdgeType arc[MAXVEX][MAXVEX];	//邻接矩阵,边表
	int numVertexes, numEdges;	//图中顶点数和边数 
};

struct QueueNode{
	int data;	//数据域:指向图结点的索引 
	QueueNode* next;	//下一个结点 
};

struct Queue{
	QueueNode* top;		//头指针 
	QueueNode* real;	//尾指针 
	int NodeNum;	//队列结点数 
};

//初始化队列 
void InitQueue(Queue* Q){
	Q->NodeNum = 0;
	Q->top = Q->real = NULL;
}

//入队 
void EnQueue(Queue* Q, int i){
	QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
	newNode->data = i;
	newNode->next = Q->top;
	if(Q->top != NULL)
		Q->top->next = newNode;
	Q->top = newNode;
	Q->NodeNum++;
	if(Q->NodeNum == 1)	//头尾指向同一个 
		Q->real = Q->top;
}

//出队
void DeQueue(Queue* Q, int* i){
	QueueNode* deNode;
	if(Q->NodeNum != 0){
		*i = Q->real->data;
		deNode = Q->real;
		Q->real= deNode->next;
		free(deNode);
		Q->NodeNum--;
	}
} 

//判断队列是否为空
bool QueueEmpty(Queue Q){
	if(Q.NodeNum == 0)
		return 1;
	return 0;
}
 
/* 建立无向图的邻接矩阵表示 */
void CreateMGraph(MGraph* G){
	int i, j, k, w;
	printf("输入顶点数和边数:\n");
	scanf("%d,%d",&G->numVertexes, &G->numEdges);
	printf("输入顶点值(字符):\n");
	for(i=0;i<G->numVertexes;i++){//读取顶点信息,建立顶点表 
		getchar();	//吃掉回车 
		scanf("%c", &G->vexs[i]);
	}
	for(i=0;i<G->numVertexes;i++)
		for(j=0;j<G->numVertexes;j++)
			G->arc[i][j] = INFINITY;	//邻接矩阵初始化
	for(k=0;k<G->numEdges;k++){	//读取numEdges条边,建立邻接矩阵 
		printf("输入边(vi,vj)上的下标i,下标j和权w:\n");
		scanf("%d,%d,%d",&i,&j,&w);
		G->arc[i][j] = w;
		G->arc[j][i] = G->arc[i][j];	//无向图的邻接矩阵关于主对角线对称 
	}
}

void DFS(MGraph* G, int i){
	int j;
	visited[i] = true;
	printf("%c",G->vexs[i]);
	for(j=0;j<G->numVertexes;j++)
		if(G->arc[i][j] == 1 && !visited[j])
			DFS(G, j);	//对未访问的邻接 
}

/* 深度优先遍历 */ 
void DFSTraverse(MGraph* 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);
}

/* 广度优先遍历 */
void BFSTraverse(MGraph* G){
	int i, j, k;
	Queue Q;
	for(i=0;i<G->numVertexes;i++)	//初始化遍历数组 
		visited[i] = false; 
	InitQueue(&Q);	//初始化辅助用的队列
	for(i=0;i<G->numVertexes;i++){
		if(!visited[i]){
			k = i;
			visited[i] = true;
			printf("%c",G->vexs[i]);
			EnQueue(&Q, i);
			while(!QueueEmpty(Q)){
				DeQueue(&Q, &i);
				for(j=0;j<G->numVertexes;j++){
					if(G->arc[i][j] == 1 && !visited[j]){
						visited[j] = true;
						printf("%c",G->vexs[j]);
						EnQueue(&Q, j);
					}
				}
			}
			i = k;
		}
	}
}

int main(){
	MGraph* G = (MGraph*)malloc(sizeof(MGraph));
	CreateMGraph(G);
	printf("深度优先遍历:\n");
	DFSTraverse(G);
	printf("\n广度优先遍历:\n");
	BFSTraverse(G);
	return 0;
} 
结果

图遍历例子结果

邻接表实现
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

#define MAXVEX 10
typedef char VertexType;	//顶点类型
typedef int EdgeType;	//边上的权值类型

bool visited[MAXVEX];	//标记访问的结点

struct QueueNode{
	int data;	//数据域:指向图结点的索引 
	QueueNode* next;	//下一个结点 
};

struct Queue{
	QueueNode* top;		//头指针 
	QueueNode* real;	//尾指针 
	int NodeNum;	//队列结点数 
};

//初始化队列 
void InitQueue(Queue* Q){
	Q->NodeNum = 0;
	Q->top = Q->real = NULL;
}

//入队 
void EnQueue(Queue* Q, int i){
	QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
	newNode->data = i;
	newNode->next = Q->top;
	if(Q->top != NULL)
		Q->top->next = newNode;
	Q->top = newNode;
	Q->NodeNum++;
	if(Q->NodeNum == 1)	//头尾指向同一个 
		Q->real = Q->top;
}

//出队
void DeQueue(Queue* Q, int* i){
	QueueNode* deNode;
	if(Q->NodeNum != 0){
		*i = Q->real->data;
		deNode = Q->real;
		Q->real = deNode->next;
		free(deNode);
		Q->NodeNum--;
		if(Q->NodeNum == 0)
			Q->top = NULL;
	}
} 

//判断队列是否为空
bool QueueEmpty(Queue Q){
	if(Q.NodeNum == 0)
		return 1;
	return 0;
} 

struct EdgeNode{
	int adjvex;	//邻接点域,存储下标
	EdgeType weight;	//权值
	EdgeNode* next;	//下一个邻接点 
};

struct VertexNode{	//顶点表结点 
	VertexType data;	//顶点域,存储顶点信息
	EdgeNode* firstedge;	//边表头指针 
};

struct GraphAdjList{	//邻接表 
	VertexNode adjList[MAXVEX];
	int numVertexes, numEdges;	//图中当前顶点数和边数 
};

/*无向图邻接表创建*/
void CreateALGraph(GraphAdjList* G){
	int i, j, k;
	EdgeNode* newNode;
	printf("输入顶点和边数:\n");
	scanf("%d,%d",&G->numVertexes, &G->numEdges);
	printf("输入顶点值:\n");
	for(i=0;i<G->numVertexes;i++){
		getchar();	//吃掉回车 
		scanf("%c",&G->adjList[i].data);
		G->adjList[i].firstedge = NULL;	//将邻接表置空
	} 
	for(k=0;k<G->numEdges;k++){
		printf("输入边(vi,vj)下标\n");
		scanf("%d,%d", &i ,&j);
		//生成2个结点链接到头结点 
		newNode = (EdgeNode*)malloc(sizeof(EdgeNode));
		newNode->adjvex = i;
		newNode->next = G->adjList[j].firstedge;
		G->adjList[j].firstedge = newNode;
		
		newNode = (EdgeNode*)malloc(sizeof(EdgeNode));
		newNode->adjvex = j;
		newNode->next = G->adjList[i].firstedge;
		G->adjList[i].firstedge = newNode;
	}
}

/* 广度优先遍历 */
void BFSTraverse(GraphAdjList* G){
	int i, k;
	Queue Q;
	EdgeNode* e;
	InitQueue(&Q);	//初始化队列 
	for(i=0;i<G->numVertexes;i++)
		visited[i] = false;
	for(i=0;i<G->numVertexes;i++){
		k = i;
		if(!visited[i]){
			visited[i] = true;
			printf("%c",G->adjList[i].data);
			EnQueue(&Q, i);
			while(!QueueEmpty(Q)){
				DeQueue(&Q, &i);
				e = G->adjList[i].firstedge;	//拿到i结点的头指针
				while(e){
					if(!visited[e->adjvex]){
						visited[e->adjvex] = true;
						printf("%c",G->adjList[e->adjvex].data);
						EnQueue(&Q, e->adjvex);
					}
					e = e->next;
				} 
			}
		}
		i = k;
	}
}

void DFS(GraphAdjList* G, int i){
	
	EdgeNode* e;
	visited[i] = true;
	printf("%c",G->adjList[i].data);
	e = G->adjList[i].firstedge;	//拿到头指针 
	while(e){
		if(!visited[e->adjvex])
			DFS(G, e->adjvex);
		e = e->next;
	}
}

/* 深度优先遍历 */
void DFSTraverse(GraphAdjList* 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);
		}
	}
}

/* 销毁图 */
void DestoryGraph(GraphAdjList* G){
	int i;
	EdgeNode* e;
	EdgeNode* temp;
	if(G){
		for(i=0;i<G->numVertexes;i++){
			e = G->adjList[i].firstedge;	//拿到头指针
			if(e){
				temp = e;
				e = temp->next;
				free(temp);
			}
		}
		free(G);
	}
}

int main(){
	GraphAdjList* G = (GraphAdjList*)malloc(sizeof(GraphAdjList));
	CreateALGraph(G);
	printf("\n深度优先遍历:");
	DFSTraverse(G);
	printf("\n广度优先遍历:");
	BFSTraverse(G);
	printf("\n");
	DestoryGraph(G);
	return 0;
}
结果

图遍历结果(邻接表)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值