图搜索算法BFS和DFS通俗易懂的图示详解以及各自优缺点
一、图解
1.BFS
BFS即广度优先搜索算法(Breadth-First-Search),是一种利用队列实现的搜索算法。
假设起点为西宁,要找到石家庄。
我们可以把搜索的过程比作是打仗,目前我们的据点只有西宁,而与西宁连接的城市有三个,分别是银川、兰州、成都,所以下一步计划就是攻占这三个城市之一,因此把这三个城市加入队列。
父节点 | 西宁 | 西宁 | 西宁 | ||||||
---|---|---|---|---|---|---|---|---|---|
子节点 | 银川 | 兰州 | 成都 |
由于是队列数据结构,也就是先进先出,所以先攻打银川,占领银川以后,把银川弹出队列,把下一步要占领的城市,也就是银川的邻居城市西安和太原加入队列。(由于银川的另外两个邻居兰州和西宁已经被访问过,所以不再考虑)
父节点 | 西宁 | 西宁 | 西宁 | 银川 | 银川 | ||||
---|---|---|---|---|---|---|---|---|---|
子节点 | 兰州 | 成都 | 西安 | 太原 |
接下来攻占兰州,由于兰州的所有邻居城市已被访问过,所以不需要添加新的节点到队列。
父节点 | 西宁 | 西宁 | 西宁 | 银川 | 银川 | ||||
---|---|---|---|---|---|---|---|---|---|
子节点 | 成都 | 西安 | 太原 |
然后攻占成都,攻占后把成都尚未被访问过的邻居城市重庆加入队列
父节点 | 西宁 | 西宁 | 西宁 | 银川 | 银川 | 成都 | |||
---|---|---|---|---|---|---|---|---|---|
子节点 | 西安 | 太原 | 重庆 |
接着攻占西安,把西安尚未访问过的邻居城市郑州和武汉加入队列
父节点 | 西宁 | 西宁 | 西宁 | 银川 | 银川 | 成都 | 西安 | 西安 | |
---|---|---|---|---|---|---|---|---|---|
子节点 | 太原 | 重庆 | 郑州 | 武汉 |
此时攻占太原,把太原尚未访问过的邻居城市石家庄加入队列,这样就找到了目标城市石家庄。
父节点 | 西宁 | 西宁 | 西宁 | 银川 | 银川 | 成都 | 西安 | 西安 | 太原 |
---|---|---|---|---|---|---|---|---|---|
子节点 | 重庆 | 郑州 | 武汉 | 石家庄 |
但直到目标城市石家庄被弹出时,搜索才会结束,所以接下来还要依次攻占重庆,郑州,武汉,直到石家庄被弹出,搜索结束。
父节点 | 西宁 | 西宁 | 西宁 | 银川 | 银川 | 成都 | 西安 | 西安 | 太原 |
---|---|---|---|---|---|---|---|---|---|
子节点 |
石家庄被弹出后回溯,石家庄的父节点为太原,太原父节点为银川,银川父节点为西宁
父节点 | 西宁 | 西宁 | 西宁 | 银川 | 银川 | 成都 | 西安 | 西安 | 太原 |
---|---|---|---|---|---|---|---|---|---|
子节点 |
这样就找到了最短的一条路径,即
西宁 --> 银川 --> 太原 --> 石家庄
2.DFS
DFS即深度度优先搜索算法(Bepth-First-Search),是一种利用栈结构实现的搜索算法。栈结构的特点是先进后出。
仍然以改图为例,以西宁为起点搜索石家庄。
目前我们的据点只有西宁,而与西宁连接的城市有三个,分别是银川、兰州、成都,所以下一步计划就是攻占这三个城市之一,因此把这三个城市加入队列。
父节点 | 西宁 | 西宁 | 西宁 | ||||||
---|---|---|---|---|---|---|---|---|---|
子节点 | 银川 | 兰州 | 成都 |
由于成都是最后加入栈的,所以它最先被攻占,攻占之后把它弹出栈,并将它未被访问过的邻居城市重庆加入栈。
父节点 | 西宁 | 西宁 | 西宁 | 成都 | |||||
---|---|---|---|---|---|---|---|---|---|
子节点 | 银川 | 兰州 | 重庆 |
此时重庆变成了最后加入栈的城市,所以攻占重庆并把它尚未被访问过的邻居城市武汉、西安加入栈。
父节点 | 西宁 | 西宁 | 西宁 | 成都 | 重庆 | 重庆 | |||
---|---|---|---|---|---|---|---|---|---|
子节点 | 银川 | 兰州 | 武汉 | 西安 |
于是西安最后被加入,所以攻占西安并把它未被访问过的邻居城市太原、郑州加入栈
父节点 | 西宁 | 西宁 | 西宁 | 成都 | 重庆 | 重庆 | 西安 | 西安 | |
---|---|---|---|---|---|---|---|---|---|
子节点 | 银川 | 兰州 | 武汉 | 太原 | 郑州 |
此时郑州是最后入栈的城市,所以弹出郑州并把它未被访问过的邻居城市石家庄加入栈
父节点 | 西宁 | 西宁 | 西宁 | 成都 | 重庆 | 重庆 | 西安 | 西安 | 郑州 |
---|---|---|---|---|---|---|---|---|---|
子节点 | 银川 | 兰州 | 武汉 | 太原 | 石家庄 |
此时石家庄最后入栈,所以把它弹出,搜索宣告结束
父节点 | 西宁 | 西宁 | 西宁 | 成都 | 重庆 | 重庆 | 西安 | 西安 | 郑州 |
---|---|---|---|---|---|---|---|---|---|
子节点 | 银川 | 兰州 | 武汉 | 太原 |
石家庄被弹出后栈中还有银川、兰州、武汉、太原四个城市,但我们的目标城市已经找到,所以没有必要再去处理他们,而是直接进行回溯,石家庄父节点为郑州,郑州父节点为西安,西安父节点为重庆,重庆父节点为成都,成都父节点为西宁,这样就找到了从西宁到石家庄的一条路径,即
西宁 --> 成都 --> 重庆 --> 西安 --> 郑州 --> 石家庄