C++实现深度遍历迷宫问题

题目要求

深度遍历搜索迷宫路径

	输入要求:
   		1、请输入迷宫的行列数(例如:10 10)
   		2、请输入迷宫的路径信息(0表示可以走,1表示不能走)
   		3、输入示例:
   			0 0 0 1 1
   			1 0 0 0 1
   			1 1 0 1 1
   			1 1 0 0 1
   			1 1 1 0 0

	输出要求:
    	1、如果没有路径,直接输出 : 不存在一条迷宫路径!
    	2、如果有路径,直接输出   :  将路径上的0改为*号然后输出!
    		* * * 1 1
    		1 0 * 0 1
    	    1 1 * 1 1
    	    1 1 * * 1
    		1 1 1 * *

深度遍历迷宫解题思路

  1. 首先大家需要了解深度遍历的思想、即在遍历过程中、总是在一个方向上一直找、直到不能在往下走、然后在切换方向、因此我们需要事先规定好寻找方向的顺序(此处给出的方向是 右->下->左->上),那么在遍历每个节点时、先判断当前节点的右方向是否能走、如果能走就直接进入当前节点的右边节点、否则才去判断当前节点的下边是否能走、以此类推,直到找到路径或者没有路径
  2. 因为是深度遍历、因此借助递归的思想、此处我们C++STL容器适配器的栈、帮助完成深度遍历
  3. 我们先将判断入口节点(左上角第一个节点)、如果入口节点是1、那就说明迷宫没有入口、直接返回并打印没有路径,否则就先将第一个节点入栈、然后取出栈顶元素(此时的栈顶元素就是第一个元素),按照上述方式判断当前节点的下一个节点是否位0,也就是能不能走,(注意此处判断的顺序),如果能走就将下一个节点入栈,如果不能走,就将当前节点出栈、最后栈中元素就是路径,当然前提是栈不为空,如果栈为空,就是没有找到路径
  4. 另外需要注意的一个点就是找过的节点就不再能在找、否则会出现环

注意:我们在这里需要对每个节点进行简单的封装,首先我们每个节点肯定必须有自己的横纵坐标,自己的状态(0或者1),还有一个重要的信息需要写入每个节点中,就是节点四个方向上的节点的状态(0或者1),这里单独将节点信息列出来

节点代码

const int DIR_SIZE = 4;

struct Node
	{
		int nx;    // 横坐标
		int ny;    // 纵坐标
		int nval;  // 状态值
		bool nstats[DIR_SIZE];  // 四个方向的状态值
	};

迷宫代码

#include <iostream>
#include <stack>     // STL容器适配器的stack
using namespace std;

//表示方向、注意四个值刚好对应节点中保存四个方向状态信息的下标
const int RIGHT = 0;
const int DOWN = 1;
const int LEFT = 2;
const int UP = 3;

// 表示存储方向数组的大小(四个方向)
const int DIR_SIZE = 4;

// 表示状态信息
const bool YES = true;  // 表示可以走
const bool NO = false;  // 表示不能走

// 迷宫类
class Maze
{
private:
	// 需要迷宫每个节点的类型、此处因此每个节点都有自己的x、y坐标、自己的状态(0,1)
	// 以及自己四个方向上的是否能走的、因此使用结构体来封装节点
	struct Node
	{
		int nx;    // 横坐标
		int ny;    // 纵坐标
		int nval;  // 状态值
		bool nstats[DIR_SIZE];  // 四个方向是否能走
	};

	Node** marr;           // 迷宫相当于是个二维表
	int mrow;              // 迷宫的行
	int mcol;              // 迷宫的列
	stack<Node> mstack;    // 深度遍历迷宫使用栈存储迷宫中最终找到的路径节点

public:
	Maze(int row, int col)
		: mrow(row)
		, mcol(col)
	{
	   // 动态开辟二维数组
		marr = new Node*[row];
		for (int i = 0; i < row; ++i)
		{
			marr[i] = new Node[col];
		}
	}
	~Maze()
	{
		for (int i = 0; i < mrow; ++i)
		{
			delete[]marr[i];
		}
		delete[]marr;

		marr = nullptr;
	}

	// 初始化每个节点的状态信息、并将节点四个方向上都先设置为不能走、
	void init_maze(int x, int y, int val)
	{
		marr[x][y].nx = x;
		marr[x][y].ny = y;
		marr[x][y].nval = val;
		for (int i = 0; i < DIR_SIZE; ++i)
		{
			marr[x][y].nstats[i] = NO;
		}
	}

	// 在初始化完成以后每个节点都知道自己四个方向是否能走、并将其设置到节点的方向数组中
	void set_dir_stats()
	{
		for (int i = 0; i < mrow; ++i)
		{
			for (int j = 0; j < mcol; ++j)
			{
				// j < mcol -1 防止最右边一列元素访问越界
				if (j < mcol - 1 && marr[i][j + 1].nval == 0)
				{
					marr[i][j].nstats[RIGHT] = YES;
				}
				// i < mrow -1 防止最下边一行元素访问越界
				if (i < mrow - 1 && marr[i + 1][j].nval == 0)
				{
					marr[i][j].nstats[DOWN] = YES;
				}
				// j > 0 防止最左边一列元素访问越界
				if (j > 0 && marr[i][j - 1].nval == 0)
				{
					marr[i][j].nstats[LEFT] = YES;
				}
				// i > 0 防止最上边一行元素访问越界
				if (i > 0 && marr[i - 1][j].nval == 0)
				{
					marr[i][j].nstats[UP] = YES;
				}
			}
		}
	}

	// 深度遍历迷宫、寻找路径
	void traverse_maze_find_path()
	{
		// 表示第一个节点都不能进入、即该迷宫没有入口
		if (marr[0][0].nval == 1) 
		{
			return;
		}

		// 否则就是有入口、先将第一个节点放入栈中
		mstack.push(marr[0][0]); 
		
		while (!mstack.empty())
		{
			// 每次拿出栈顶元素进行判断
			int x = mstack.top().nx;
			int y = mstack.top().ny;

			// 表示已经找到最后一个元素了
			if (x == mrow - 1 && y == mcol - 1)
			{
				return;
			}

			// 此处使用判断顺序是右 -》 下 -》 左 -》 上 
			// 右
			if (marr[x][y].nstats[RIGHT] == YES)
			{
				// 首先设置限制、防止死循环
				// 如果走到下一个节点后发现这个节点是个死胡同、然后跳回前一个节点
				// 再次判断时就不再走这个节点了、而是往其他方向寻找出路
				// 如果不进行设置、就会在这两个节点上来回跳跃、形成死循环
				marr[x][y].nstats[RIGHT] = NO;
				marr[x][y + 1].nstats[LEFT] = NO;
				mstack.push(marr[x][y + 1]);
				continue;
			}
			// 下
			if (marr[x][y].nstats[DOWN] == YES)
			{
				marr[x][y].nstats[DOWN] = NO;
				marr[x + 1][y].nstats[UP] = NO;
				mstack.push(marr[x + 1][y]);
				continue;
			}
			// 左
			if (marr[x][y].nstats[LEFT] == YES)
			{
				marr[x][y].nstats[LEFT] = NO;
				marr[x][y - 1].nstats[RIGHT] = NO;
				mstack.push(marr[x][y - 1]);
				continue;
			}
			// 上
			if (marr[x][y].nstats[UP] == YES)
			{
				marr[x][y].nstats[UP] = NO;
				marr[x - 1][y].nstats[DOWN] = NO;
				mstack.push(marr[x - 1][y]);
				continue;
			}

			// 如果当前节点的四个方向都不能左、就让当前节点出栈(栈顶元素)
			mstack.pop();
		}
	}

	// 输出深度遍历结果
	void show_maze_path()
	{
		if (mstack.empty())
		{
			cout << "不存在一条迷宫路径!" << endl;
			return;
		}
		
		// 将路径上的元素设置为*
		while (!mstack.empty())
		{
			Node cur = mstack.top();
			marr[cur.nx][cur.ny].nval = '*';
			mstack.pop();
		}

		for (int i = 0; i < mrow; ++i)
		{
			for (int j = 0; j < mcol; ++j)
			{
				if (marr[i][j].nval == '*')
				{
					cout << "*" << " ";
				}
				else
				{
					cout << marr[i][j].nval << " ";
				}
			}
			cout << endl;
		}
	}

};


int main()
{
	int row;
	int col;
	cout << "请输入迷宫的行列数(例如:10 10): " << endl;
	cin >> row >> col;

	// 初始话一个迷宫对象
	Maze maze(row, col);

	int data = 0;
	cout << "请输入迷宫的路径信息(0表示可以走,1表示不能走): " << endl;
	for (int i = 0; i < row; ++i)
	{
		for (int j = 0; j < col; ++j)
		{
			cin >> data;
			maze.init_maze(i, j, data);
		}
	}

	// 设置每个方向上能否走的状态
	maze.set_dir_stats();
	// 深度遍历迷宫寻找路径
	maze.traverse_maze_find_path();
	// 输出深度遍历结果
	maze.show_maze_path();

	return 0;
}

总结:大家一定要细心体会,如果有不懂可以多画一画图,有助于自己理解!

发布了9 篇原创文章 · 获赞 3 · 访问量 209

猜你喜欢

转载自blog.csdn.net/weixin_43604792/article/details/103087398
今日推荐