深度优先遍历DFS和宽度优先遍历BFS

深度优先遍历和宽度优先遍历,其实算法原理都很相似,区别在于

**深度遍历:只有当一个节点的所有后代被访问完,才会访问同层的下一个节点;

宽度遍历: 只有同层的所有节点访问完,才会继续访问下一层节点**

因此在设计算法时,深度遍历可以借助栈,先压当前节点再压后代,就保证了不会漏掉该节点的每一个后代,先后顺序也不会乱;而宽度遍历借助队列,则保证了每次压入队列时先弹出的都是同一层的节点。

深度优先遍历(DFS)

原理:
借助栈的先进后出性质,并准备一个辅助记录数组(记录该节点之前是否已经打印过);

  1. 先将头结点压入栈中并打印头结点的值,并记录在辅助数组中。
  2. 开始循环, 从栈中弹出一个节点,挨个访问该节点的后代。如果当前访问的后代不在记录数组中(换言之,没有打印过),则先将该节点压入栈中,再将当前后代压入栈中,并且打印当前后代的值,同时记录在辅助数组中,此时不再访问该节点的下一个后代,直接break结束当前的for循环。
  3. 从外围的大循环开始,重新从栈中弹出一个节点(此时弹出的节点,按照压入栈的顺序和先进后出的性质,就是上一轮循环中的后代节点),访问该节点的后代节点是否已经打印过,没有执行压入栈中等操作,如果已经打印过,则查看下一个后代是否打印过,不断重复上述过程。
  4. 栈为空时,结束整个循环

代码如下:

DFS:

def dfs(node):

    stack = [] # 辅助栈
    had = set() # 记录用,判断一个节点是否已经被打印过,这里没用数组,用的集合

    stack.append(node)
    had.add(node)
    print(node.value)

    while (len(stack) != 0):
        cur = stack.pop()
        for n in cur.nexts: # 遍历该节点的后代
            if n not in had: # 判断该后代是否已经打印过
                stack.append(cur) # 注意顺序,要先将父节点压入
                stack.append(n) # 再压入该后代节点
                print(n.value)
                had.add(n) # 记录
                break # 跳出for循环

宽度优先遍历(BFS)

借助队列,一个辅助记录集合

  1. 开始还是先将头结点压入队列,并打印、记录
  2. 开始循环,从队列中弹出一个节点,开始遍历该节点的每个后代,与DFS中有所不同的是,它是遍历完一个节点的所有后代以后才结束当前的for循环,遍历时检查每个后代是否在记录集合中,如果在集合中表示已经打印过,则跳过,继续检查下一个后代;如果不在集合中,则压入队列,并记录打印;
  3. 当前节点的所有后代都遍历一遍之后,再次回到大循环,队列弹出一个节点,继续循环检查该节点的所有后代;
  4. 队列为空时,结束整个流程。

代码如下:

import queue

def bfs(node):
    if node == None:
        return None
    had = set() # 记录一个节点是否已经出现过
    q = queue.Queue() # 队列保证打印顺序

    had.add(node)
    q.put(node)
    print(node.value)
    
    while (not q.empty()):
        cur = q.get() # 
        # print(cur.value)
        for n in cur.nexts:
            if n not in had: # 如果该节点没有进过(换言之,没有打印过)则记录并压入队列,否则跳过
                had.add(n)
                q.put(n)
                print(n.value) # 进集合就打印
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值