BFS 广度优先搜索

BFS 广度优先搜索_第1张图片

     广度优先搜索BFS(Breadth First Search)也称为宽度优先搜索,它是一种先生成的结点先扩展的策略,类似于树的层次遍历

    在广度优先搜索算法中,解答树上结点的扩展是按它们在树中的层次进行的。首先生成第一层结点,同时检查目标结点是否在所生成的结点中,如果不在,则将所有的第一层结点逐一扩展,得到第二层结点,并检查第二层结点是否包含目标结点,……,对层次为n+1的任一结点进行扩展之前,必须先考虑层次完层次为n的结点的每种可能的状态。因此,对于同一层结点来说,求解问题的价值是相同的,可以按任意顺序来扩展它们。通常采用的原则是先生成的结点先扩展。

    为了便于进行搜索,要设置一个表存储所有的结点。由于在广度优先搜索算法中,要满足先生成的结点先扩展的原则,所以存储结点的表一般采用队列这种数据结构。

    在编写程序时,可用数组q模拟队列。

front和rear分别表示队头指针和队尾指针,初始时front=rear=0。

元素x入队操作为  q[rear++]=x;

元素x出队操作为  x =q[front++];

广度优先搜索算法的搜索步骤一般是:

(1)从队列头取出一个结点,检查它按照扩展规则是否能够扩展,如果能则产生一个新结点。

(2)检查新生成的结点,看它是否已在队列中存在,如果新结点已经在队列中出现过,就放弃这个结点,然后回到第(1)步。否则,如果新结点未曾在队列中出现过,则将它加入到队列尾。

(3)检查新结点是否目标结点。如果新结点是目标结点,则搜索成功,程序结束;若新结点不是目标结点,则回到第(1)步,再从队列头取出结点进行扩展。


    最终可能产生两种结果:找到目标结点,或扩展完所有结点而没有找到目标结点。

    如果目标结点存在于解答树的有限层上,广度优先搜索算法一定能保证找到一条通向它的最佳路径,因此广度优先搜索算法特别适用于只需求出最优解的问题。当问题需要给出解的路径,则要保存每个结点的来源,也就是它是从哪一个节点扩展来的。

对于广度优先搜索算法来说,问题不同则状态结点的结构和结点扩展规则是不同的,但搜索的策略是相同的。广度优先搜索算法的框架一般如下:

void  BFS()

{

    队列初始化;

    初始结点入队;

    while (队列非空)

    {  

          队头元素出队,赋给current;

          while  (current 还可以扩展)

          {

              由结点current扩展出新结点new;

              if  (new 重复于已有的结点状态) continue;

              new结点入队;

              if  (new结点是目标状态)

              {

                    置flag= true;    break; 

               }

          }

      }
}

    对于不同的问题,用广度优先搜索法的算法基本上都是一样的。但表示问题状态的结点数据结构、新结点是否为目标结点和是否为重复结点的判断等方面则有所不同。对具体的问题需要进行具体分析,这些函数要根据具体问题进行编写。


接下来从一个经典的迷宫问题引入:哔哩哔哩完整视频讲解

BFS 广度优先搜索_第2张图片

关于搜索方向:
BFS 广度优先搜索_第3张图片

测试用例:

5 4
1 1 2 1
1 1 1 1
1 1 2 1
1 2 1 1
1 1 1 2
1 1 4 3

输出:

7

详细代码:

#include
#include
using namespace std;

int m, n;//输入的地图大小 m行 n列
int map[100][100];//地图数组 0为边界 1为可走 2为障碍
int v[100][100];//访问数组 1为已访问 0为未访问

//四个方向: 右、下、左、上
int dx[4] = {0,1,0,-1};
int dy[4] = {1,0,-1,0};

//标识是否搜索到
bool flag = false;

class Point {  //创建节点
public:
	int x;
	int y;
	int step;
};
queue<Point> r;//创建队列

int main() {
	cin >> m >> n;
	//从1开始循环 可以避免数组越界 因为最外层有一圈0 来作“墙”
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			cin >> map[i][j];
		}
	}
	int start_x, start_y,end_x,end_y;
	cin >> start_x >> start_y >> end_x >> end_y;

	//BFS 广度优先搜索
	Point start;
	start.x = start_x;
	start.y = start_y;
	start.step = 0;
	r.push(start);//将起点入队
	v[start.x][start.y] = 1;//把起点设置为已访问 1
	while (!r.empty()) {
		int x = r.front().x;
		int y = r.front().y;

		if (x == end_x && y == end_y) /*找到终点*/{
			flag = true;
			cout << r.front().step;
			break;
		}
		//从四个方向搜索
		for (int i = 0; i <= 3; i++) {
			int tx = x + dx[i];
			int ty = y + dy[i];
			if (map[tx][ty] == 1 && v[tx][ty] == 0) {//如果地图能走,且未访问
				//入队
				Point temp;
				temp.x = tx;
				temp.y = ty;
				temp.step = r.front().step + 1;
				r.push(temp);
				v[tx][ty] = 0;
			}
		}
		r.pop();//四个方向搜索完了需要将队首元素出队
	}
	if (flag==false) {
		cout << "没有找到";
	}
	return 0;
}
/*测试用例:
5 4
1 1 2 1
1 1 1 1
1 1 2 1
1 2 1 1
1 1 1 2
1 1 4 3
*/

宽搜BFS 和 深搜DFS 的比较:

BFS 广度优先搜索_第4张图片

你可能感兴趣的:(数据结构算法之美,宽度优先,算法)