一、算法框架
int BFS(Node start, Node target)
{
Queue<Node> q = new Queue<Node>();
HashSet<Node> visited = new HashSet<Node>();
q.Enqueue(start);
visited.Add(start);
int count = 0;
while(q.Count != 0)
{
int sz = q.Count;
//对距离初始点count距离的所有点进行查找看是否满足要求
for(int i = 0 ; i < sz ; i++)
{
Node cur = q.Dequeue();
//找到结果,返回距离count
if(cur == target)
return count;
//没有找到结果,继续往所有节点的下一层进行搜索
//由于多叉树每个节点都不相同,因而不需要visited结构
//但是对于有重复子问题的结构,可能走回头路的结构就需要visited结构
foreach(var item in cur.children)
{
if(item != null && !visited.Contains(item))
{
q.Enqueue(item);
visited.Contains(item);
}
}
}
//在这里增加路径长度
count++;
}
}
二、两个问题
1、为什么 BFS 可以找到最短距离,DFS 不行吗?(BFS是齐头并进)
首先,你看 BFS 的逻辑,depth
每增加一次,队列中的所有节点都向前迈一步,这保证了第一次到达终点的时候,走的步数是最少的。
DFS 不能找最短路径吗?其实也是可以的,但是时间复杂度相对高很多。
你想啊,DFS 实际上是靠递归的堆栈记录走过的路径,你要找到最短路径,肯定得把二叉树中所有树杈都探索完才能对比出最短的路径有多长对不对?
而 BFS 借助队列做到一次一步「齐头并进」,是可以在不遍历完整棵树的条件下找到最短距离的。
形象点说,DFS 是线,BFS 是面;DFS 是单打独斗,BFS 是集体行动。
2、既然 BFS 那么好,为啥 DFS 还要存在?(BSF空间复杂度高)
BFS 可以找到最短距离,但是空间复杂度高,而 DFS 的空间复杂度较低。
还是拿刚才我们处理二叉树问题的例子,假设给你的这个二叉树是满二叉树,节点总数为N
,对于 DFS 算法来说,空间复杂度无非就是递归堆栈,最坏情况下顶多就是树的高度,也就是O(logN)
。
但是你想想 BFS 算法,队列中每次都会储存着二叉树一层的节点,这样的话最坏情况下空间复杂度应该是树的最底层节点的数量,也就是N/2
,用 Big O 表示的话也就是O(N)
。
由此观之,BFS 还是有代价的,一般来说在找最短路径的时候使用 BFS,其他时候还是 DFS 使用得多一些(主要是递归代码好写)。
三、BFS和DFS时间复杂度是一样的,将图表示为临界矩阵时为N2,表示为邻接链表时为N+e