图及图的搜索算法
一、图论
图论是数学的一个分支,它以图为研究对象
图论中的图是由若干给定的点及连接两点的线所构成的图形,这种图形通常同来描述事物之间的某种特定关系,用点代表事物,用连接两点的线表示相应两个事物之间有这种关系
二、图的结构
非线性结构
有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&¤tPoint.col == endPoint.col)
break;//退出while循环
if (s.empty())
break;//就是说,没有找到这个终点,把元素压进栈后,又把所有的元素弹出来了
}
//将路径打印出来
while (!s.empty())//栈不为空才能打印
{
MyPoint tempPoint = s.top();
//从栈顶开始打印
printf("row=%d, col=%d
", tempPoint.row, tempPoint.col);
s.pop();
}
return 0;
}