数据结构篇十六:图的深搜和广搜二

图的深搜和广搜

前面一篇是利用深搜和广搜进行图的顶点的遍历,今天我们则是根据起点和终点位置进行路径的搜索。

图的深搜算法

问题:假设现在有一无向图,我现在要给你一个起始点和终点,如果可以走通请输出一条简单路径,不能则返回无路径。

思考:我们可以考虑用深度搜索去求解此问题,我们假设用邻接矩阵存储这个图。我们可以设计一个数组去保存搜索过程的路径。

注意点:算法的设计关键就是利用深搜递归可以回退参数的特点去求解,但是由于c语言的普通数组,传递的参数都是实参,无法进行回退,所以我们需要自定义伪数组去实现真正的形参,这样我们可以回退数组的结果。

深搜步骤

  • 设计一个空数组,用于保存搜索整个过程经过的点,数组必须是可以回退的形参(数组作为函数参数比较特殊,它是引用传递,函数的直接修改)
  • 在搜索的递归函数开始时,初始将起点添加到数组里,然后凡是和起点有关的都进行递归,于是到了第二层递归时,和起点有关的一个点又作为起点放入新的形参数组继续调用递归,,直到发现某个点等于终点,就输出数组的保存的路径,递归结束。

图示案例

我先用个形象的图,演示下递归处理的过程,假设我们要搜索A到F是否有一条简单路径。
我们就是让A先进去第一层递归,把A放入数组,接着B,C,D都和A有关联,依次进入各自的递归函数,然后进入B,C,D的那些点带着自己的数组,又作为起点将和它相连的点依次进入递归函数,整个过程就有以下搜索过程

  • A–>B–>E–>F
  • A–>C–>E–>F
  • A–>D–>G–>H

在这里插入图片描述

深搜代码

//深搜的辅助操作
void Find_Path(struct MGraph *g, char obj1, char obj2)
{
	int index1, index2,*temp;
	struct Array arr;
	arr.len = 0;
	temp = (int*)malloc(sizeof(int) * g->numVretexes);
	for (int i = 0; i < g->numVretexes; i++)
	{
		if (g->vetex[i] == obj1)
		{
			index1 = i;
		}
		if (g->vetex[i] == obj2)
		{
			index2 = i;
		}
		temp[i] = 0;
	}
	DFS_Search(g, arr, temp, index1, index2);
}

//深搜的核心
void DFS_Search(struct MGraph *g, struct Array arr,int *temp, int obj1, int obj2)
{
	temp[obj1] = 1;
	arr.data[arr.len++] = obj1;
	if (obj1 == obj2)//找到了路径,输出路径
	{
		for (int i = 0; i < arr.len; i++)
		{
			printf("%c ", g->vetex[i]);
		}
		printf("\n");
	}
	for (int j = 0; j < g->numVretexes; j++)
	{
		if (g->data[obj1][j] != 0 && temp[j]==0)//有关联的点
		{
			DFS_Search(g, arr,temp, j, obj2);
		}
	}
}

图的广搜算法

问题:假设现在有一无向图,我现在要给你一个起始点和终点,请输出一条最短的行走方案。(最短就是指走过的边数最少)

思考:此时的问题已经是在寻找路径的基础上增加了一条最短路径的问题,注意此处的最短路径不是说求带权值的最短路径,此处的最短路径求的是按边的个数计算。走过的边最少的路径。

方案: 因为广度优先遍历,是逐层逐层的找,所以它肯定会在第一时间内找到我们要找的点,当然它对应的路径也就是经过边的个数一定是最少的。我们在进行广度优先遍历的基础上为每个点增加前驱标记,标记每个点的前驱是谁,这样我们就可以回退输出最短路径了。忘记广度优先遍历的可以看前一篇关于广度优先遍历的介绍。

过程演示

在这里插入图片描述

假设我们要寻找点A到点E的最短路径问题。

  1. 初始化队列queue和前驱数组path,并让点A入队列。
队列元素A
dataABCDE
前驱顶点

2.出队一个元素,A出队列,和A有关联的点都入队列,即B与F都入队列,修改入队点B和F的前驱是A

队列元素BF
dataABCDEF
前驱顶点AA

3.出队一个元素,B出队列,和B有关的都入队列,被访问的点不用入队列。所以C和D入队列,修改点C和点D的前驱是B

队列元素FCD
dataABCDEF
前驱顶点ABBA

4.出队列一个元素,所以F出队列,和F有关的都入队列,所以E入队列,修改点E的前驱是F,此时E节点找到了,直接退出。

队列元素CDE
dataABCDEF
前驱顶点ABBFA

好了,我们只需要查看最终的前驱数组,就可以得到最短路径了,终点E的前驱是F,F的前驱是A,到达了起点A,所以最终的最短路径就是A-F-E了。

广搜代码

void Find_Path(struct MGraph *g, char obj1, char obj2)
{
	int index1, index2, *temp,*pre,*queue,front,rear,num;
	temp = (int*)malloc(sizeof(int) * g->numVretexes);
	queue = (int*)malloc(sizeof(int) * g->numVretexes);//辅助队列
	pre = (int*)malloc(sizeof(int) * g->numVretexes);
	front = rear = 0;
	for (int i = 0; i < g->numVretexes; i++)
	{
		temp[i] = 0;
		pre[i] = -1;//前驱顶点
		if (obj1 == g->vetex[i])
		{
			index1 = i;
		}
		if (obj2 == g->vetex[i])
		{
			index2 = i;
		}
	}
	queue[rear++] = index1;
	temp[index1] = 1;
	while (front != rear)
	{
		num = queue[front++];
		if (num == index2)//找到了目标点,逆序打印路径
		{
			while (pre[num]!=-1)
			{
				printf("%c ", g->vetex[num]);
				num = pre[num];
			}
			printf("%c ", g->vetex[num]);
			printf("\n");
		}
		//出队列时,将所有有关联的点入队列
		for (int i = 0; i < g->numVretexes; i++)
		{
			if (g->data[num][i] != 0 && temp[i] == 0)
			{
				temp[i] = 1;
				queue[rear++] = i;
				pre[i] = num;//设置顶点的前驱
			}
		}
	}
}

获取完整代码

我分别用C,C++,JAVA三种主流语言编写了完整代码,有需要的在微信公众号搜索考研稳上岸获取完整代码

数据结构练习(同样适用于考研)

微信小程序搜索计算机刷题
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值