数据结构之图的邻接表实现(包含BFS、DFS的实现)

后附代码
基础知识
有向图中
孤立点:V中不与E中任一条边关联的点称为D的孤立点.
简单图:不含平行边的图称为简单图.
完备图:图中任两个顶点U与u之间,恰有两条有向边(u,v),及(v,u),则称该有向图D为完备图.
基本图:把有向图D的每条边除去定向就得到一个相应的无向图G,称G为D的基本图.称D为G的定向图。
强连通图:给定有向图G=(VE),并且给定该图G中的任意两个结点u和v,如果结点u与结点v相互可达,即至少存在一条路径可以由结点u开始,到结点v终止,同时存在至少有一条路径可以由结点v开始,到结点u终止,那么就称该有向图G是强连通图。
弱连通图:若至少有一对结点不满足单向连通,但去掉边的方向后从无向图的观点看是连通图,则D称为弱连通图。
单向连通图:若每对结点至少有一个方向是连通的,则D称为单向连通图。
强连通分支:有向图G的极大强连通子图称为该有向图的强连通分支。
有向通路:无环有向图D中总存在这样一个独立集5,使得y—Js中任何一点",存在H∈S,从M到"有长度不超过2的有向通路。

有向图

有向图是一个二元组,其中1.V是非空集合,称为顶点集。2.E是V×V的子集,称为弧集。
通俗点就是有方向的图
无向图

边没有方向的图称为无向图。

直观来说,若一个图中每条边都是无方向的,则称为无向图。
(1)无向边的表示
无向图中的边均是顶点的无序对,无序对通常用圆括号表示。
【例】无序对(vi,vj)和(vj,vi)表示同一条边。
(2)无向图的表示
【例】下面(b)图中的G2和©图中的G3均是无向图,它们的顶点集和边集分别为:

V(G2)={v1,v2,v3,v4}
E(G2)={(vl,v2),(v1,v3),(v1,v4),(v2,v3),(v2,v4),(v3,v4)}
V(G3)={v1,v2,v3,v4,v5,v6,v7}
E(G3)={(v1,v2),(vl,v3),(v2,v4),(v2,v5),(v3,v6),(v3,v7)}
(3)若G是无向图,则0≤e≤n(n-1)/2
恰有n(n-1)/2条边的无向图称无向完全图(Undirected Complete Graph)

DFS(深度优先搜索)
深度优先遍历图的方法是,从图中某顶点v出发:
(1)访问顶点v;
(2)依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问;
(3)若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。

BFS(广度优先搜索)
假设从图中某顶点出发,先访问了V之后依次访问V的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问他们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直至图中所有已被访问的顶点的邻接点都被访问到。

DFS和BFS的区别
源自 https://blog.csdn.net/sunny04/article/details/41911655
广度优先搜索(BFS),可以被形象的描述为“浅尝辄止”,具体一点就是每个顶点只访问它的邻接节点(如果它的邻接节点没有被访问)并且记录这个邻接节点,当访问完它的邻接节点之后就结束这个顶点的访问。

广度优先用到了“先进先出”队列,通过这个队列来存储第一次发现的节点,以便下一次的处理;而对于再次发现的节点,我们不予理会——不放入队列,因为再次发现的节点:
1、无非是已经处理完的了;
2、或者是存储在队列中尚未处理的。

深度优先搜索(DFS),可以被形象的描述为“打破沙锅问到底”,具体一点就是访问一个顶点之后,我继而访问它的下一个邻接的顶点,如此往复,直到当前顶点一被访问或者它不存在邻接的顶点。
1、WHITE 未访问顶点
2、GRAY 一条深度搜索路径上的顶点,即被发现时
3、BLACK 此顶点的邻接顶点被全部访问完之后——结束访问次顶点

DFS和BFS的优缺点
BFS:占内存多,能找到最优解,必须遍历所有分枝. 广优的一个应用就是迪科斯彻单元最短路径算法.
DFS:占内存少,能找到最优解(一定条件下),但能很快找到接近解(优点),可能不必遍历所有分枝(也就是速度快), 深优的一个应用就是连连看游戏.

在更多的情况下,深优是比较好的方案。

代码:

#include
#include
#include
#define MAX 100
//链表
typedef struct node{
	int adjvexData;			/*邻接点域*/
	struct node *next;	    /*指向下一邻接点的指针域*/
}AD;
//首链表
typedef struct tnode{
	char firstData;          /*顶点域*/
	AD *firstedge;			/*指向第一条边结点*/
}FD;
//首数组
typedef struct{
	FD arr[MAX];			/*邻接表头结点数组*/
	int n,l;				/*顶点数、边数*/
}Arr; 
//构建图 
void create (Arr &M,int flag){
	int m,j,i,n,num1,num2;
	AD *p,*p1;
	printf("输入图的顶点数\n");
	scanf("%d",&M.n);
	printf("输入图的边数\n");
	scanf("%d",&M.l);
	printf("请输入图的各项信息\n");
	for(i=0;iadjvexData=num2;
		p->next=M.arr[num1].firstedge;
		M.arr[num1].firstedge=p;
		if(flag==0){				//无向图 
			p=(AD *)malloc(sizeof(AD));
			p->adjvexData=num1;
			p->next=M.arr[num2].firstedge;
			M.arr[num2].firstedge=p;
		}
	}
}
int visit[MAX];			//用于判断是否遍历到 
//深度优先递归算法 
void DFS(Arr M,int i){
	AD *p;
	visit[i]=1;
	printf("%c-->",M.arr[i].firstData);
	p=M.arr[i].firstedge;
	while(p){
		if(!visit[p->adjvexData])     
			DFS(M,p->adjvexData);
		p=p->next;
	}
}
//深度遍历操作
void DFSTraverse(Arr M){
	int i;
	for(i=0;in;i++){
		printf("%2d [%c]",i,M->arr[i].firstData);
		p=M->arr[i].firstedge;
		while(p){
			printf("-->[%d]",p->adjvexData);
			p=p->next;
		}
		printf("\n");
	}
} 
//广度优先搜索
void BFS(Arr *M){
	int i,v;
	int qu[MAX],front=0,rear=0;			//循环队列 
	AD *p; 
	for(i=0;in;i++){
		visit[i]=0;
	}
	printf("%C-->",M->arr[0].firstData);
	visit[0]=1;
	rear=(rear+1)%MAX;				   //队尾指针后移 
	while(front!=rear){
		front=(front+1)%MAX;
		v=qu[front];				   //将队头元素出队
		p=M->arr[v].firstedge;
		while(p!=NULL){
			if(visit[p->adjvexData]==0){
				visit[p->adjvexData]=1;
				printf("%c-->",M->arr[p->adjvexData].firstData);
				rear=(rear+1)%MAX;
				qu[rear]=p->adjvexData;	
			}
			p=p->next;
		} 
	}	
} 

int main(){
	int flage;
	Arr M;
	printf("输入建立图的类型(1有向图 0无向图)\n");
	scanf("%d",&flage);
	create(M,flage);
	printf("邻接表\n");
	DisAGraph(&M);
	printf("深度优先搜索\n");
	DFSTraverse(M); 
	printf("\n广度优先搜索\n");
	BFS(&M);
	return 0;
} 

你可能感兴趣的:(数据结构)