一、课程目标
- 队列
- 广度优先搜索
- 算法实现
- 求最短路
二、目标详解
1、队列
队列是一种数据结构,只能从队尾加入元素,从队首弹出元素,特性就是先进入队列的元素先出队,简称FIFO(First In First Out)。
c++的stl里提供了队列容器queue,如下:
- 头文件:#include <queue>
- 变量:queue<int> q;
- 入队:q.push(x); //插入x到队尾
- 出队:q.pop(); //删除队首的元素(没有获取)
- 访问:q.front(); //访问对首的元素
- 判空:q.empty();
- 个数:q.size();
2、广度优先搜索
从某个顶点v0出发,依次访问其相邻的每个点,然后逐层向外访问,直到没有可访问点(或找到解)为止。
上图从A点出发进行bfs遍历(蓝色字表示访问顺序):
- 访问A点(出队),邻接点有B、F、G,入队后队列为BFG
- 访问B点(出队),邻接点有C、D,入队后队列为FGCD
- 访问F点(出队),邻接点无,队列为GCD
- 访问G点(出队),邻接点为D、H,入队后队列为CDH(D重复不再入队)
- 访问C点(出队),邻接点无,队列为DH
- 访问D点(出队),邻接点为E,入队后队列为HE
- 访问H点(出队),邻接点无,队列为E
- 访问E点(出队),邻接点无,队列为空
- 循环结束
bfs遍历序列为:ABFGCDHE
可以发现,整个遍历过程是分层进行的,先遍历距离为1的所有顶点,再距离为2的所有顶点,···,直到访问完毕。在距离为x的层未访问完成之前,不会访问距离为x+1的层。
层次结构如下图:
3、算法实现
伪代码:
bfs()
起点入队
while (队列不空)
访问队首元素、出队
for 队首元素相邻结点
入队并标记
使用stl的queue容器:
void bfs(int v0) {
queue<int> q;
vis[v0] = true;
q.push(v0);
while(!q.empty()) {
int tmp = q.front();
cout<<tmp;
q.pop();
for(tmp的所有邻接点i) {
if(vis[i]) continue;
vis[i] = true;
q.push(i);
}
}
}
4、求最短路
三、扩展理解-dfs与bfs
1、广搜的理解
你的眼镜掉了,你趴在地板上找,先摸一圈最近的地方,如果没有,再往远一点摸过去…..
2、空间复杂度
dfs占用的是栈的空间(因为递归),每次遍历需要占用等于路径深度的栈空间。
bfs占用的是队列的空间,每次遍历需要占用等于邻接点数目的队列空间。
从空间复杂度来说:
- 链状图:bfs好于dfs,用bfs的空间占用只有1个,而dfs就要占用链深度大小的空间。
- 星状图:dfs好于bfs,用bfs的空间占用邻接点数目大小,而dfs只有一层深度。
3、应用场景
bfs适合用于找一条最短路径(无权图),既一个最优解,也可以理解成一种贪心策略。
dfs使用找所有(最短)路径,既遍历所有的解空间,进行判定,也可以理解成枚举策略。
问题
:为什么说bfs使用找无权图的最短路径?