概述
BFS最简单的方式如下:
BFS()
{
初始化队列
while(队列不为空且未找到目标节点)
{
取队首节点扩展,并将扩展出的非重复节点放入队尾;
}
}
示例题简介
下面以一经典LeetCode(题号:172)为例看一下BFS的写法。
给定一个其实单词和一个终止单词,从起始单词出发,每次在所给单词列表中找一个单词有且只有一个字母与当前单词不同,如果能到达终止单词,返回最短路径的长度。
BFS
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
//unordered_set是hash表实现,用于快速查字符串。
unordered_set<string> dict(wordList.begin(), wordList.end());
if (dict.find(endWord) == dict.end()) {
return 0;
}
queue<string> q;
//初始化队列,将第一个结点加入。
q.push(beginWord);
int step = 1;
while(!q.empty()) {
//q存有当前层级的所有结点,因为上此while循环中还要加入下一层的结点,所以在这里要先保当前层结点的数目保存下来,一次while循环只遍历一层结点。
int n = q.size();
//遍历当前层
for(int i = 0; i < n; i++) {
// 取队首节点扩展
string word = q.front();
q.pop();
//找到目前字符串则直接返回
if (word == endWord) {
return step;
}
//访问过的结点标记一下,这里是直接删除。
dict.erase(word);
//找到可变一个字符的单词
for(int j = 0; j < word.size(); j++) {
char oldC = word[j];
for(char c = 'a'; c <= 'z'; c++) {
word[j] = c;
if (dict.find(word) != dict.end()) {
//加入下一层结点
q.push(word);
}
}
//restore
word[j] = oldC;
}
}
//层级数+1
step++;
}
//not found
return 0;
}
双向BFS
双向BFS是BFS的扩展,指从起点和终点同时搜索,直接两者有交点,表明搜索成功。
BFS搜索过程示例(与当前题输入/输出无关):
双向BFS搜索过程示例(与当前题输入/输出无关),可以很明显的看到减少了起码一半的时间。以当前题来看是(1372 ms->44ms)的差距,差距非常明显。
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
//双向BFS
unordered_set<string> dict(wordList.begin(), wordList.end()), head, tail;
if (dict.find(endWord) == dict.end()) {
return 0;
}
head.insert(beginWord);
tail.insert(endWord);
int step = 2;
while(!head.empty() && !tail.empty()) {
//保持两边队列大小平衡,有更好的搜索效果。
if (head.size() > tail.size()) {
swap(head, tail);
}
//保存下一层结点
unordered_set<string> nextLevel;
//把当前层结点(head)遍历完
for(auto it = head.begin(); it != head.end(); ++it) {
string word = *it;
//word在加入前已经检查过不是交点,直接去搜索下一层结点(可变一个字符的单词)
for(int j = 0; j < word.size(); j++) {
char oldC = word[j];
for(char c = 'a'; c <= 'z'; c++) {
word[j] = c;
//查看与另一队列是否有交点
if (tail.find(word) != tail.end()) {
return step;
}
if (dict.find(word) != dict.end()) {
dict.erase(word);
nextLevel.insert(word);
}
}
//restore
word[j] = oldC;
}
}
swap(head, nextLevel);
step++;
}
//not found
return 0;
}