广度寻路算法C++实现

广度寻路算法C++实现


广度寻路和深度寻路算法是两种常用的图形搜索算法,当然这里的寻路,是指在一个二维平面上,我们将平面划分为许多个方格,给定目的地和起始地,寻找到一条起点到终点之间的路径。广度寻路算法能找到最短路径,而深度寻路算法并不保证找到的路径是最短的路径。但由于广度寻路算法中的循环嵌套比较多,耗费资源大,因此广度寻路算法更适合用于小一点的地图场景。而深度寻路算法就更适合开阔的大地图。
本篇文章来介绍广度寻路算法,有关深度寻路算法的之后再更。
所谓广度寻路,就是将起点作为根节点构造一棵树,每个结点的孩子结点就是这个结点代表的位置能到达的位置。比如下面这个地图:

在这里插入图片描述
红色方框是起点,蓝色方框是终点,深红色的区域代表障碍物无法通行。起点的坐标设为(0,0),那么起点的孩子结点就只有(0,1),也就是它下面那个方框,因为这个起点能到达的只有这一个地方。以此类推(0,1)的孩子结点就是(1,1)和(0,2)。
按照这个思路构建树的过程中,当我们遍历到终点时,就意味着起点到终点的路径出现了。我们的树结构中,每个结点都有指向自己父节点的指针,根据这个指针我们可以从终点找到回去的“路”。另外在树的遍历过程中,需要理解“层”的概念,因为我们是一层一层的进行遍历整颗树的,为了方便直接用一个容器vector来存放一个结点的所有子节点,这样做可以省去许多指针操作,毕竟每个结点的子节点数量并不相同。
实现代码如下:

// 广度寻路算法.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <string.h>
#include <vector>
using namespace std;

#define ROWS   10
#define COLS   10

struct MyPoint{
	int row;
	int col;
};

struct pathNode{
	int		val;		//地图上的值
	bool	isFind;		//是否走过
};

//树节点
struct treeNode{
	MyPoint				pos;
	treeNode*			pParent;//指向父节点的指针
	vector<treeNode*>	child;	//存储指向所有孩子节点指针的容器
};

//能走返回true 否则返回false
bool canWalk(pathNode pathMap[ROWS][COLS], MyPoint pos);


int _tmain(int argc, _TCHAR* argv[])
{
	//1. 地图
	int map[ROWS][COLS] = {
		{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
		{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
		{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
		{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
	};

	//2 起点和终点
	MyPoint begPos = { 0, 0 };
	MyPoint endPos = { 0, 9 };

	//3 辅助地图
	pathNode pathMap[ROWS][COLS] = { 0 };
	for (int i = 0; i < ROWS; i++){
		for (int j = 0; j < COLS; j++){
			pathMap[i][j].val = map[i][j];
		}
	}

	//4 准备一颗树,起点成为树根节点
	treeNode* pRoot = NULL;//准备树

	pRoot = new treeNode;//开内存
#if 1
	memset(pRoot, 0, sizeof(treeNode));//全部置空
	pRoot->pos = begPos;
#else
	pRoot->pos = begPos;
	pRoot->pParent = NULL;
#endif
	//5 标记起点走过
	pathMap[begPos.row][begPos.col].isFind = true;

	//6 寻路
	MyPoint temp;
	//当前节点
	treeNode* pCurrent = NULL;
	//新节点
	treeNode* pChild = NULL;
	//当前层
	vector<treeNode*> currentBuff;
	
	//下一层
	vector<treeNode*> nextBuff;
	bool isFindEnd = false;

	currentBuff.push_back(pRoot);
	while (1)
	{//一层一层变化
		nextBuff.clear();//清空数组
		for (int i = 0; i < currentBuff.size(); i++){//遍历当前层
			pCurrent = currentBuff[i];
			for (int j = 0; j < 4; j++){//四个方向找相邻节点
				temp = pCurrent->pos;
				switch (j){
				case 0://上
					temp.row--;
					break;
				case 1://下
					temp.row++;
					break;
				case 2://左
					temp.col--;
					break;
				case 3://右
					temp.col++;
					break;
				}
				if (canWalk(pathMap,temp)){//能走
					//创建新节点
					pChild = new treeNode;
					memset(pChild, 0, sizeof(treeNode));
					pChild->pos = temp;
					//新节点入树
					pCurrent->child.push_back(pChild);	//新节点成为当前节点的孩子
					pChild->pParent = pCurrent;			//当前节点成为新节点的父
					//标记走过
					pathMap[temp.row][temp.col].isFind = true;
					//新节点进入下一层
					nextBuff.push_back(pChild);
					//是否是终点
					if (temp.row == endPos.row &&
						temp.col == endPos.col){
						isFindEnd = true;
						break;
					}
				}
			}
			if (isFindEnd) break;
		}
		if (isFindEnd) break;
		//整个地图都遍历完毕,也没有找到终点
		if (nextBuff.size() == 0) break;
		currentBuff = nextBuff;//当前层变化
	}

	if (isFindEnd){
		printf("找到终点啦!\n");
		printf("path:");
		while (pChild){
			printf("(%d,%d) ", pChild->pos.row, pChild->pos.col);
			pChild = pChild->pParent;
		}
		printf("\n");
	}

	while (1);
	return 0;
}

//能走返回true 否则返回false
bool canWalk(pathNode pathMap[ROWS][COLS], MyPoint pos){
	//不在地图范围内
	if (pos.row < 0 || pos.col >=COLS || pos.row >= ROWS || pos.col < 0) return false;

	//走过
	if (pathMap[pos.row][pos.col].isFind) return false;
	//是障碍
	if (pathMap[pos.row][pos.col].val) return false;

	return true;
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值