【数据结构与算法】广度寻路算法(树结构)

广度寻路算法的思想

将实际地图抽象为树(四叉树,四个方向)。起点就是树的根节点,是树的第一层。走一步能到达的节点都是根节点的孩子,是树的第二层。走两步能到达的节点是树的第三层…当树的叶子到达终点或没有地方拓展了,寻路结束。
在这里插入图片描述
找到终点后一路往上回溯,一直追溯到起点,这条路径就是最佳路径。

树的结构

enum dir{e_up,e_right,e_down,e_left};
typedef struct Point
{
	int x, y;
}Point;
typedef struct treeNode
{
	Point pt;
	struct treeNode* parent;
	struct treeNode* arr[4];//孩子数组
	int arrSize;//孩子个数
}treeNode;

创建结点

treeNode* creatTree(int row, int col)
{
	treeNode* pNew = malloc(sizeof(struct treeNode));
	if (NULL == pNew) return NULL;

	memset(pNew, 0, sizeof(struct treeNode));
	pNew->pt.x = row;
	pNew->pt.y = col;
	return pNew;
}

寻路准备

  • 地图,辅助地图(判断某个位置有没有走过,走过则为true,走过了则之后不能再走)。

  • 规定起始点,终点,试探点(帮助看能否移动)。

  • 准备一颗树,起始点作为树根。

  • 利用数组存储树的当前层结点和下一层结点

  • 树根首先进入当前层数组

//地图
	int map[ROW][COL] = {
		{0,1,0,0,0,0,0,0,0,0},
		{0,1,0,1,0,1,0,1,1,1},
		{0,1,0,1,0,0,0,0,0,1},
		{0,0,0,1,0,1,0,0,0,1},
		{0,1,0,0,0,0,0,0,0,1},
		{0,1,0,1,0,0,0,0,0,1},
		{0,1,0,1,0,1,0,0,0,0},
		{0,1,0,1,0,0,0,1,0,1},
		{0,1,0,1,0,1,0,0,0,1},
		{1,1,1,1,1,1,1,1,1,1}
	};
	//辅助地图
	bool isFind[ROW][COL] = { 0 };
	Point begPot = { 0,0 };
	Point endPot = { 6,9 };
	isFind[begPot.x][begPot.y] = true;
	treeNode* root = creatTree(0, 0);
	//当前层
	treeNode* cur[100] = { root };
	int curSize = 1;
	//下一层
	treeNode* next[100];
	int nextSize = 0;
	//当前点
	treeNode* curNode=NULL;
	//试探点
	treeNode* temp=NULL;
	//是否找到终点
	bool isEnd=false;

寻路过程

  • 从第一层开始依次遍历每个结点
    • 每个节点都有四个方向,再依次遍历四个方向
      • 当前点为当前层对应点
      • 创建试探结点temp
      • 试探点的row col根据方向依次发生变化
      • 判断移动后的试探点的位置是否是能够正确移动的位置,即该点没有越界,不是墙壁,没有走过
        • 如果在此方向可以移动,temp成为当前点的孩子,当前点成为temp的父亲,temp存入下一层。
        • 当前层移动到下一层,重新开始遍历新的一层
        • 如果不能,则销毁temp。
        • 判断是否找到终点,如果是isEnd=true,跳出循环。
  • 重复执行步骤
    当有多条路径时,如果有一条最短的路径到达了终点,则循环停止,可以获取这条最短的路径。
while (1)
	{
		for (int i = 0; i < curSize; i++)
		{
			for (int j = 0; j < 4; j++)//向四个方向试探
			{
				curNode = cur[i];
				temp = creatTree(curNode->pt.x, curNode->pt.y);
				switch (j)
				{
				case e_up:
					temp->pt.x--;
					break;

				case e_right:
					temp->pt.y++;
					break;

				case e_down:
					temp->pt.x++;
					break;

				case e_left:
					temp->pt.y--;
					break;
				}
				//判断能不能走
				if(canWalk(temp->pt,map,isFind))
				{
					//入树
					temp->parent = curNode;
					curNode->arr[curNode->arrSize++] = temp;
					//标记走过
					isFind[temp->pt.x][temp->pt.y] = true;
					//是当前层的下一层
					next[nextSize++] = temp;
					//判断是不是终点
					if (temp->pt.x == endPot.x && temp->pt.y == endPot.y)
					{
						isEnd = true;
						break;
					}
				}
				else//不能
				{
					free(temp);
					temp = NULL;
				}
			}//end j
			if (isEnd)
				break;
		}//end i
		if (isEnd)
			break;
		if (nextSize == 0)
			break;
		//切换到下一层
		memcpy(cur, next, sizeof(treeNode*) * nextSize);
		curSize = nextSize;
		//下一层清空
		memset(next, 0, sizeof(treeNode*) * nextSize);
		nextSize = 0;

	}//end while
	if (isEnd)
	{
		printf("找到终点了\n");
		while (temp) {
			printf("(%d,%d)",
				temp->pt.x,
				temp->pt.y);

			temp = temp->parent;
		}
		printf("\n");
	}

}
bool canWalk(Point pt, int map[ROW][COL], bool isFind[ROW][COL])
{
	//越界
	if (pt.x >= ROW || pt.y >= COL || pt.x < 0 || pt.y < 0)
		return false;
	//障碍
	if (map[pt.x][pt.y]) 
		return false;
	//已经走过
	if (isFind[pt.x][pt.y]) 
		return false;

	return true;
}

打印路径

if (isEnd)
	{
		printf("找到终点了\n");
		while (temp) {
			printf("(%d,%d)",
				temp->pt.x,
				temp->pt.y);

			temp = temp->parent;
		}
		printf("\n");
	}

运行结果

在这里插入图片描述

比较深度寻路与广度寻路:

深度寻路 判断多 循环少,有回退,适用于宽阔大地图,不一定能找到最短路径,

广度寻路 判断少 循环多,没有回退。适用于小地图,如果你的地图宽阔的话用广度寻路的话就会特别慢。

相同点:都只能走直线,不能走斜线

在一个没有障碍的地图上,从点(0,0)到(9,9)

广度优先寻路算法走过的路径,不同颜色表示不同层
在这里插入图片描述
深度优先寻路算法的路径
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值