python实现图的DFS和BFS

一.理论部分

关于图的定义,在python语言中,我们可以使用字典来进行定义。

在C++语言中可以使用邻接表或者邻接矩阵来进行储存定义。在这里主要介绍python中图的DFS和BFS。

核心思想:解决图的BFS问题就是利用队列的先进先出的思想来解决问题。因为我们需要利用queue来保证树的第几层或者说是图中我们遍历走了几步的顺序。

BFS和树的层序遍历非常类似,这也是很多博客为啥只把树的前序,中序,后序遍历放在一起讲,而不把层序遍历放在一起讲的主要原因,树和图的遍历,主要区别是树有根节点,所以指定了,而图需要我们自身指定开始遍历的节点,起始节点的不同会导致遍历节点的不同。

解决图的DFS问题,其实和图的BFS类似,只是在底层用的数据结构,不一样,在图的DFS中使用的栈这个数据结构,利用先进后出的概念。

在这里我也总结一下栈可以用来解决的场景,可能不全慢慢进行优化吧,第一次总结,用来给自己或者有需要的人的在学习DFS和BFS的同时能够不仅学习到解决BFS和DFS这两种场景的算法同时,也能把这个思想用来解决其他问题,触类旁通。

使用栈时,第一,我们可以用其解决符号匹配的问题。

第二,可以用其解决递归的问题,典型的就是斐波那契数列的递归。

第三可以用用来解决四则运算表达式求值问题。里面涉及到的问题主要是后缀表示法和中缀表示法。中缀表示法就是我们常见的,下面给大家区分一下。

中缀表示法:a+b*c+(d*e+f)*g

后缀表示法:abc*+de*f+g*+

具体的中缀转后缀,后缀表达式计算大家可以看看程杰编写的《大话数据结构》,形象而有趣,特别好。

第四:在计算机中函数的调用也是利用栈的原理。

因为CPU一次只能执行一个命令,而寄存器也是公用的,

当前函数 current() 在运行时,数据储存在寄存器中,如果要调用另外一个函数 target(),而target() 也要求使用寄存器,为了防止数据丢失并且在执行完 target(),能够返回到 current() 继续执行, 这时候就要把当前函数的重要数据储存起来,压入内存中的栈中( 包括变量的值和函数地址 )。这样target()函数就可以无所顾忌的使用寄存器了。target() 函数执行结束就取栈顶的返回地址继续执行 current()。如果target()中又调用另外一个函数,相应的操作也是一样的。

这种机制和括号匹配有点相似,函数调用就像遇到了一个左括号,函数返回就像遇到一个右括号。

这种机制就是递归的原理。递归返回地址就是自己。(这句话可能有问题,我就是这么理解的)。

栈的空间有限,如果递归没有结束条件,就会不断的压栈,然后栈溢出,程序出错。所以递归的终止条件非常非常重要。

队列

第一:当多个任务分配给打印机时,为了防止冲突,创建一个队列,把任务入队,按先入先出的原则处理任务。

第二:当多个用户要访问远程服务端的文件时,也用到队列,满足先来先服务的原则。

二:Presentation of Code


#定义一个图的结构
graph={
    'A':['B','C'],
    'B':['A','C','D'],
    'C':['A','B','D','E'],
    'D':['B','C','E','F'],
    'E':['C','D'],
    'F':['D']
}
#BFS 广度优先搜索   层序遍历
def BFS(graph,s):#graph图  s指的是开始结点
    #需要一个队列
    queue=[]
    queue.append(s)
    seen=set()#看是否访问过该结点
    seen.add(s)
    while (len(queue)>0):
        vertex=queue.pop(0)#保存第一结点,并弹出,方便把他下面的子节点接入
        nodes=graph[vertex]#子节点的数组
        for w in nodes:
            if w not in seen:#判断是否访问过,使用一个数组
                queue.append(w)
                seen.add(w)
        print(vertex)       
#DFS指的是深度优先搜索    回溯法(会回看前面的节点)
#一直往前走,走不下去往回跳
#使用stack来进行深度的顺序
#把栈顶元素去除,在把临接点放入


#其实并不难,只要把队列改成栈就可以了
def DFS(graph,s):#图  s指的是开始结点
    #需要一个队列
    stack=[]
    stack.append(s)
    seen=set()#看是否访问过
    seen.add(s)
    while (len(stack)>0):
        #拿出邻接点
        vertex=stack.pop()#这里pop参数没有0了,最后一个元素
        nodes=graph[vertex]
        for w in nodes:
            if w not in seen:#如何判断是否访问过,使用一个数组
                stack.append(w)
                seen.add(w)
        print(vertex)

猜你喜欢

转载自blog.csdn.net/weizhifei1234/article/details/88787352