图及深度优先搜索

图及图的搜索算法

一、图论

图论是数学的一个分支,它以图为研究对象

图论中的图是由若干给定的点及连接两点的线所构成的图形,这种图形通常同来描述事物之间的某种特定关系,用点代表事物,用连接两点的线表示相应两个事物之间有这种关系

二、图的结构

非线性结构

有n个直接前趋,n个直接后继

三、图的组成

由两部分组成,一部分叫点的集合,另一部分叫边的集合

四、图的分类

1.无向图,图中的边是节点的无序对(即两节点不分谁是起始点,谁是终止点),则此图称为无向图。通常有圆括号表示无向边

2.有向图。图中边是节点的有序对,则称此图为有向图。有向边又称为弧,通常用尖括号表示一条有向边

3.有向完全图与无向完全图。在图中的任何一个点,和其他所有的点都有边连接

五、深度优先

1.规则

沿着一个固定的方向进行行走,到了岔路口才又一次选择方向,如果碰到了死胡同退回上一个岔路口重新选择方向,走过的路就不会再重新走,一次走一个岔路口

注意:因为方向设定不一样,可能最终找到的路径是不一样的。跟默认的方向有关,默认的方向选的好,那么可能路径就比较短,如果选的不好,有可能路径就很远

方向的设置会极大的影响寻路的效率

六、深度优先搜索代码实现

#include<iostream>
using namespace std;

//1.有图(二维数组)
#define MAP_ROW 10
#define MAP_COL 10

//准备一个结构来表示路径点的类型
struct MyPoint
{
	int row, col; 
};

//准备一个方向,表示搜索的行进方向
enum PathDir
{
	p_up,p_down,p_left,p_right
};

//4.准备一个数据结构用来保存搜索后的路径点数据
#include<stack>


//5.准备一个辅助地图,为搜索做辅助操作,避免修改资源
struct PathNode
{
	int val;//用来保存原始资源的路径点信息
	PathDir dir;//在当前节点上搜索方向
	bool isFind;//标记是否已访问
};


bool checkPoint(PathNode p[][MAP_COL], int row, int col)
{
	//判断当前row,col是否越界
	if (row < 0 || row >= MAP_COL || col < 0 || col >= MAP_COL)
		return false;

	//判断当前位置为障碍或已被访问过
	if (p[row][col].val != 0 || p[row][col].isFind)
		return false;
	return true;
}

int main()
{
	//点的集合
	int arr[MAP_ROW][MAP_COL] = {
		{1,1,0,1,1,1,1,1,1,1},
		{1,1,0,1,1,1,1,1,1,1},
		{1,1,0,0,0,0,0,0,1,1},
		{1,1,1,0,1,0,1,0,1,1},
		{1,1,1,0,1,0,1,0,1,1},
		{1,1,1,0,1,0,1,0,1,1},
		{1,1,0,0,1,0,1,0,1,1},
		{1,1,0,1,1,0,1,1,1,1},
		{1,1,0,0,1,0,1,1,1,1},
		{1,1,1,1,1,1,1,1,1,1},
	};
	//准备一个结构体数组
	PathNode pathArr[MAP_ROW][MAP_COL];

	for (int i = 0; i < MAP_ROW; i++)
	{
		for (int j = 0; j < MAP_COL; j++)
		{
			//相当于一个初始化的操作

			//保存路径点信息
			pathArr[i][j].val = arr[i][j];

			//表示所有的路径点都没有被访问
			pathArr[i][j].isFind = false;

			//设置每一个坐标点的初始方向为上
			pathArr[i][j].dir = p_up;
		}
	}
	//辅助数组准备完成

	//先保存起点和终点信息
	MyPoint beginPoint = { 0,2 };
	MyPoint endPoint = { 6,7 };

	//用栈容器保存起点信息
	stack<MyPoint> s;
	s.push(beginPoint);//先将起点信息压进栈


	//因为要用起点来进行搜索,但是起点信息不能改变,所以要定义一个辅助坐标,用来找其他位置
	MyPoint currentPoint = beginPoint;



	//然后开始搜索
	while (true)//不知道怎么结束,就一直循环
	{  
		switch (pathArr[currentPoint.row][currentPoint.col].dir)
		{
			//就是寻路方向:上--》下--》左--》右
		case p_up:
			pathArr[currentPoint.row][currentPoint.col].dir = p_down;//这一行表示,如果不可通行的话,还是要改变方向,因为你不能确定你下面的路一直是通的,如果下面的路不通的话,往回退到这里,就不用走以前走过的路了
			if (checkPoint(pathArr, currentPoint.row - 1, currentPoint.col))
			{
				//表示可通行

				//要标记当前路径点已经被访问了
				pathArr[currentPoint.row][currentPoint.col].isFind = true;
				//改变当前路径点寻路方向,表示如果通行之后,再次回退到这个路径点,下一次的搜索方向
				//pathArr[currentPoint.row][currentPoint.col].dir = p_down;

				//如果可以通行的话,就要把这个可以通行的路径点信息保存到栈中,所以要用一个临时变量来保存这个路径点
				MyPoint tempPoint = { currentPoint.row - 1, currentPoint.col };
				//入栈
				s.push(tempPoint);
				//保存完之后,还要改变当前寻路点的信息
				currentPoint = tempPoint;
			}
			//else
			//{
			//	//表示不可通行
			//	//不可通行就要改变方向
			//	pathArr[currentPoint.row][currentPoint.col].dir = p_down;
			//}
			break;
		case p_down:
			pathArr[currentPoint.row][currentPoint.col].dir = p_left;
			if (checkPoint(pathArr, currentPoint.row + 1, currentPoint.col))
			{
				pathArr[currentPoint.row][currentPoint.col].isFind = true;
				MyPoint tempPoint = { currentPoint.row + 1, currentPoint.col };
				s.push(tempPoint);
				currentPoint = tempPoint;
			}
			break;
		case p_left:
			pathArr[currentPoint.row][currentPoint.col].dir = p_right;
			if (checkPoint(pathArr, currentPoint.row , currentPoint.col-1))
			{
				pathArr[currentPoint.row][currentPoint.col].isFind = true;
				MyPoint tempPoint = { currentPoint.row, currentPoint.col-1 };
				s.push(tempPoint);
				currentPoint = tempPoint;
			}
			break;
		case p_right:
			if (checkPoint(pathArr, currentPoint.row, currentPoint.col+1))
			{
				pathArr[currentPoint.row][currentPoint.col].isFind = true;
				MyPoint tempPoint = { currentPoint.row, currentPoint.col+1 };
				s.push(tempPoint);
				currentPoint = tempPoint;
			}
			else
			{
				//并不是右方向才加else,而是四个搜索方向上的最后一个方向上才加else
				//出栈,就是说不能通行的话,就只能将路径点弹出栈,然后往后面寻路
				//退栈之前,要将栈顶的元素标记为已访问
				MyPoint tempPoint = s.top();
				pathArr[tempPoint.row][tempPoint.col].isFind = true;
				s.pop();
				//让当前路径点指向这个栈的最后一个元素--路径点
				
				//empty()如当前堆栈为空,empty() 函数 返回 true 否则返回false.
				if(!s.empty())//栈不为空才能得到栈顶元素
					currentPoint = s.top();
			}
			break;
		default:
			break;
		}
		if (currentPoint.row == endPoint.row&&currentPoint.col == endPoint.col)
			break;//退出while循环
		if (s.empty())
			break;//就是说,没有找到这个终点,把元素压进栈后,又把所有的元素弹出来了
	}

	//将路径打印出来
	while (!s.empty())//栈不为空才能打印
	{
		MyPoint tempPoint = s.top();
		//从栈顶开始打印
		printf("row=%d,\tcol=%d\n", tempPoint.row, tempPoint.col);
		s.pop();
	}


	return 0;
}
posted @ 2021-04-09 16:59  kisfly  阅读(75)  评论(0编辑  收藏  举报