zoukankan      html  css  js  c++  java
  • 树的层次遍历的几种方法

    --------转自 每日一道算法题  公众号

    树的遍历是一个基础问题,也有很多的实际应用,可以用来找到匹配的字符串、文本分词和文件路径等问题。

    数的遍历有两个基本的方法:深度优先遍历 和 广度优先遍历 。

    深度优先遍历又根据处理节点的顺序不同,可以分为:中序遍历、前序遍历和后序遍历。这些知识点也是深度优先遍历经常考察的。

    广度优先遍历的考察在于层次遍历,比如需要我们按照层次输出一棵树的所有节点的组合(LeetCode 107),比如求一棵树的最左节点(LeetCode 513).这些

    问题本质上都是考察的广度优先遍历。

    如下代码是经典的广度优先遍历实现的方式,使用了队列的FIFO的方式,将所有暂未访问的节点存入一个队列,依次遍历。

    queue = [node]  // 新建一个队列,并将根节点放入队列
    while queue.length != 0
        item = queue.shift   // 弹出队列的头部元素
        do_someting(item)  // 操作该节点:比如存入一个数组或者打印
        queue.push(item.left)  if item.left    // 将左子节点存入队列
        queue.push(item.right) if item.right  // 将右子节点存入队列

    但是只掌握了上面的遍历方法是不够的,层次遍历的难点在于 层次的比较 。也就是说,我们需要对不同层次的节点做 隔离 

    --------------------------------------------正文---------------------------------------------------------------------------------------------------------------------------------------------

    遍历技巧一: 数组长度做隔离

    思路:

    获取当前的队列的长度length,一次只遍历length个节点,后续加入的元素在下一次循环遍历。

    伪代码如下:

    1 queue =  [node]  // 新建一个队列,并将根节点放入队列
    2 while queue.lengh != 0
    3     length = queue.length //  获取当前队列的长度
    4     while length > 0        // 只弹出length 个节点
    5         item = queue.shift // 弹出队列的头部元素
    6         do_something(item)    //  操作该节点:比如存入一个数组或者打印
    7         queue.push(item.left)  if item.left  // 将左子节点存入队列
    8         queue.push(item.right) if item.right  // 将右子节点存入队列
    9         length--

    遍历技巧二:使用分隔符

    思路

    在不同的节点中间加入一个分隔符,遍历发哦分割几点的时候,停止当前遍历。

    伪代码如下:

    1 queue = [node]     // 新建一个队列,并将根节点放入到队列
    2 while queue.lengh != 0
    3     queue.push "$"    // 将分割符放入队列
    4     while(true)           // 做一个无限循环
    5            item = queue.shift   // 弹出队列的头部元素
    6            break if item == '$'   // 如果当前的节点等于分隔符,说明该层已经遍历到了最右边
    7            do_something(item)  //操作该节点
    8            queue.push(item.left)  if item.left // 将左子节点存入队列
    9            queue.push(item.right)  if item.right // 将右子节点存入队列

    遍历技巧三:使用深度优先搜索

    思路:

    用一个level字段来保存深度,在深度优先遍历的时候,判断一下当前结点的深度即可

    伪代码如下:

     1 ans = []  // 用一个数组来保存值
     2 level = 0 // 根节点的level 是0
     3 visit(node,ans,level)
     4 
     5 
     6 def visit(node,ans,level):
     7       return if node is null  // 如果节点为空,则返回
     8     //逻辑处理部分
     9     if ans.lengh > level   //说明之前访问过该层的节点
    10            ans.[level].push node.val
    11      else               //说明之前level没有访问过
    12            ans.[level] = [node.val]
    13 visit (node.left, level +,ans)
    14 visit (node.right, level +,ans)

    逻辑处理部分的代码还有一个需要注意的地方,比如LeetCode 107 需要求reverse后的结果,所以处理这一部分逻辑代码时,需要找到当前level对应的数组的position。

    总结

    树的难点在于树的构造,需要将一般性问题抽象成一棵树,需要定义好节点和路径。当我们构造好一棵树后,一般只需要遍历这棵树就能得到结果。所以树的遍历是一个基础问题。

    其中分层遍历的技巧比dfs/bfs更难点,需要有更强的逻辑思维能力。

  • 相关阅读:
    矩阵问题
    链表问题
    PHP8确认支持JIT,加上Swoole后快到飞起
    五面阿里,顺利拿下PHP研发岗offer,这些技术点你未必掌握了
    php-laravel框架用户验证(Auth)模块解析(一)
    php laravel请求处理管道(装饰者模式)
    Redis常见七种使用场景(PHP实战)
    PHP fastcgi_finish_request 方法
    Linux 下编写一个 PHP 扩展
    创 PHP RSA2 签名算法
  • 原文地址:https://www.cnblogs.com/simplepaul/p/6721687.html
Copyright © 2011-2022 走看看