巴尔加瓦算法图解——第六章 广度优先搜索

目录

1. 介绍

2. 图是什么

3.广度优先搜索

【查找最短路径】

【队列】

4.实现图

5. 实现算法

【运行时间】

【拓扑排序】

6. 小结


❑ 学习使用新的数据结构图来建立网络模型。

❑ 学习广度优先搜索,你可对图使用这种算法回答诸如“到X的最短路径是什么”等问题。

❑ 学习有向图和无向图。

❑ 学习拓扑排序,这种排序算法指出了节点之间的依赖关系。

你可以:
❑ 编写国际跳棋AI,计算最少走多少步就可获胜;

❑ 编写拼写检查器,计算最少编辑多少个地方就可将错拼的单词改成正确的单词,如将READED改为READER需要编辑一个地方;

❑ 根据你的人际关系网络找到关系最近的医生。

1. 介绍

最短路径问题(shorterst-path problem)。你经常要找出最短路径,这可能是前往朋友家的最短路径,也可能是国际象棋中把对方将死的最少步数。解决最短路径问题的算法被称为广度优先搜索。

要确定如何从双子峰前往金门大桥,需要两个步骤。

(1)使用图来建立问题模型。

(2)使用广度优先搜索解决问题。

2. 图是什么

图由节点和边组成。一个节点可能与众多节点直接相连,这些节点被称为邻居

巴尔加瓦算法图解——第六章 广度优先搜索_第1张图片

Alex 欠RAMA钱

3.广度优先搜索

❑ 第一类问题:从节点A出发,有前往节点B的路径吗?

❑ 第二类问题:从节点A出发,前往节点B的哪条路径最短?

第一类:找一个sales

自己的朋友名单 – A他是sales吗?- 是,结束。

                                                                - 不是,将A的朋友也加入查找名单

【查找最短路径】

第二类:谁是最近的sales?

朋友是一度;朋友的朋友是二度

一度关系在二度关系之前加入查找名单

【队列】

队列类似于栈,你不能随机地访问队列中的元素。队列只支持两种操作:入队和出队。

队列是一种先进先出(First In First Out,FIFO)的数据结构,而栈是一种后进先出(Last In First Out, LIFO)的数据结构【可参见阶乘计算】。

4.实现图

列表让你能够将键映射到值。在这里,你要将节点映射到其所有邻居。

graph={}

graph['you']={'Alice','Bob','Hym'}

graph['Bob']={'Tony','Jack'}

graph['Alice']={'',''}

散列表是无序的,因此添加键—值对的顺序无关紧要。

有向图(directed graph),有双肩头才意味着关系双向,否则是单向。

无向图:没肩头。两点连线直接意味着是邻居。

巴尔加瓦算法图解——第六章 广度优先搜索_第2张图片

5. 实现算法

1.创建一个队列,用于存储要拾奋码人

2从队列中弹出一个人

3检查这个人是否是sales

4.是,结束。

不是,将这个人的所有邻居加入列表。

5.回到第二步

6.如果队列为空,说明你的人际关系网中没有sales。

更新队列时,我使用术语“入队”和“出队”,但你也可能遇到术语“压入”和“弹出”。压入大致相当于入队,而弹出大致相当于出队。

from collections import deque



def person_is_seller(person):

    # Placeholder condition, modify it according to your criteria

    return person.endswith('m')



graph = {}

graph['you'] = {'Alice', 'Bob', 'Hym'}

graph['Bob'] = {'Tony', 'Jackm'}



search_queue = deque()

search_queue += graph['you']



while search_queue:  # 只要队列不为空

    person = search_queue.popleft()  # 就取出其中的第一个人

    if person_is_seller(person):  # 检查这个人是否是芒果销售商

        print(f"{person} is a seller!")

        break

    else:

        search_queue += graph.get(person, set())



else:

    print("No seller found.")

结果:Hym is a seller.

这个算法将不断执行,直到满足以下条件之一:❑ 找到一位芒果销售商;❑ 队列变成空的,这意味着你的人际关系网中没有芒果销售商。

*重复人怎么办?.set()创建无序不重复元素集。

检查一个人之前,要确认之前没检查过他,这很重要。为此,你可使用一个列表来记录检查过的人。

from collections import deque



def person_is_seller(person):

    # Placeholder condition, modify it according to your criteria

    return person.endswith('m')



graph = {}

graph['you'] = {'Alice', 'Bob', 'Hym'}

graph['Bob'] = {'Tony', 'Jackm'}



search_queue = deque()

search_queue += graph['you']



checked_people=set() #set()检查没有重复的人 括号代表调用



while search_queue:  # 只要队列不为空

    person = search_queue.popleft()  # 就取出其中的第一个人

    if person in checked_people:

        continue

    if person_is_seller(person):  # 检查这个人是否是芒果销售商

        print(f"{person} is a seller!")

        break

    else:

        search_queue += graph.get(person, set())



else:

    print("No seller found.")

【运行时间】

运行时间至少为O,检查每条边。

你还使用了一个队列,其中包含要检查的每个人。将一个人添加到队列需要的时间是固定的,即为O(1),因此对每个人都这样做需要的总时间为O(人数)。所以,广度优先搜索的运行时间为O(人数+边数),这通常写作O(V+E),其中V为顶点(vertice)数,E为边数。

【拓扑排序】

如果任务A依赖于任务B,在列表中任务A就必须在任务B后面。这被称为拓扑排序,使用它可根据图创建一个有序列表。

举例:族谱。

这种图被称为树。树是一种特殊的图,其中没有往后指的边。

6. 小结

❑ 广度优先搜索指出是否有从A到B的路径。

❑ 如果有,广度优先搜索将找出最短路径。

❑ 面临类似于寻找最短路径的问题时,可尝试使用图来建立模型,再使用广度优先搜索来解决问题。

❑ 有向图中的边为箭头,箭头的方向指定了关系的方向,例如,rama→adit表示rama欠adit钱。

❑ 无向图中的边不带箭头,其中的关系是双向的,例如,ross -rachel表示“ross与rachel约会,而rachel也与ross约会”。

❑ 队列是先进先出(FIFO)的。

❑ 栈是后进先出(LIFO)的。

❑ 你需要按加入顺序检查搜索列表中的人,否则找到的就不是最短路径,因此搜索列表必须是队列。

❑ 对于检查过的人,务必不要再去检查,否则可能导致无限循环。

你可能感兴趣的:(码上行动:巴尔加瓦算法图解,算法,宽度优先)