广度优先搜索
广度优先搜索是最简单的图搜索算法之一,也是许多重要的图算法原型。
算法描述:
给定图 $G=(V,E)$ 和一个可识别的源结点 $s$, 广度优先搜索对图 $G$ 中的边进行系统性的搜索来发现从源结点 $s$ 可以到达的所有结点。
该算法能够计算从 $s$ 到每个可达节点的最短距离(即最少边数),同时生成一颗“广度优先搜索树”。
该算法既可以用于无向图,也可以用于有向图。
该算法需要先发现所有到源结点 $s$ 的距离为 $k$ 的所有结点,之后才会去发现到源结点 $s$ 距离为 $k+1$ 的结点。
算法适用:
通常用来寻找从一个特定源结点出发的最短路径距离。
广度优先搜索树
该树以源节点 $s$ 为根节点,包含所有 $s$ 可到达的结点,树中 $s$ 到可到达节点 $v$ 的距离,即为简单图中 $s$ 到 $v$ 的最短距离。
注:搜索树中的边是图中存在的边,而删除了部分的边,构成一棵无环的图,即树。
搜索树中的边是搜索过程中搜索到该结点所依附的那个边,如下左图所示。
若出发点是 $a$,则 $a$ 通过 $1$ 搜索到 $d$,$d$ 通过 $2$ 搜索到 $b$,$d$ 通过 $3$ 搜索到 $c$,所以搜索树如下右图所示

算法实现:
需要使用到队列,因为队列结构能够保证访问时层的顺序,即:一定是当前层的结点全部出队完毕后,才轮到下一层的结点。
1. 邻接矩阵法
int visited[N];
int edges[N][N];
void BFS(int start)
{
queue<int> mq;
memset(visited, 0, sizeof(visited));
mq.push(start);
visited[start] = 1;
while(mq.empty() == false)
{
int id = mq.front();
mq.pop();
for(int i = 0; i < N; i++)
{
if(edges[id][i] == 1 && visited[i] == 0)
{
visited[i] = 1;
mq.push(i);
}
}
}
}
2. 邻接链表法(用数组模拟)
int visited[N];
vector<int> v[N];
void BFS(int start)
{
queue<int> mq;
memset(visited, 0, sizeof(visited));
mq.push(start);
visited[start] = 1;
while(mq.empty() == false)
{
int id = mq.front();
mq.pop();
for(int i = 0; i < v[id].size(); i++)
{
if(visited[i] == 0)
{
to = v[id][i];
visited[to] = 1;
q.push(to);
}
}
}
}
3. python的一个实现
graph = {
"A": ["B", "C"],
"B": ["A", "C", "D"],
"C": ["A", "B", "D", "E"],
"D": ["B", "C", "E", "F"],
"E": ["C", "D"],
"F": ["D"]
}
def BFS(graph, s):
queue = []
seen = {}
queue.append(s)
seen.add(s)
while (len(queue) > 0):
vertex = queue.pop(0)
nodes = graph[vertex]
for w in nodes:
if w not in seen:
queue.add(w)
seen.add(w)
print(vertex)
邻接链表法时间复杂度分析:
使用聚合分析法进行整体分析,每个结点入队最多一次,出队最多一次,入队和出队的时间均为 $O(1)$,因此对队列进行操作的总时间为 $O(V)$。
因此第 $21$ 行到第 $23$ 行的时间复杂度是 $O(V)$,因为这三行成线性关系,因此只考虑队列操作。
现在考虑循环和条件判断,会对每条边进行扫描,因此 $12$ 行到 $19$ 行的时间复杂度为 $O(E)$。
因此总时间复杂度为 $O(V+E)$。
浙公网安备 33010602011771号