102. 二叉树的层序遍历;深度优先遍历和广度优先遍历

深度优先遍历(DFS) 与广度优先遍历(BFS)是图论中两种非常重要的算法,生产上广泛用于拓扑排序,寻路(走迷宫),搜索引擎,爬虫等,深度优先就是自上而下的遍历搜索 广度优先则是逐层遍历

对于算法来说 无非就是时间换空间 空间换时间

  1. 深度优先不需要记住所有的节点, 所以占用空间小, 而广度优先需要先记录所有的节点占用空间大
  2. 深度优先有回溯的操作(没有路走了需要回头)所以相对而言时间会长一点
    深度优先采用的是堆栈的形式, 即先进后出
    广度优先则采用的是队列的形式, 即先进先出

深度优先遍历

主要思路是从图中一个未访问的顶点 V 开始,沿着一条路一直走到底,然后从这条路尽头的节点回退到上一个节点,再从另一条路开始走到底…,不断递归重复此过程,直到所有的顶点都遍历完成,它的特点是不撞南墙不回头,先走完一条路,再换一条路继续走。

树是图的一种特例(连通无环的图就是树),接下来我们来看看树用深度优先遍历该怎么遍历。
在这里插入图片描述
算法实现:
准备
假设页面上的dom结构如下:

<div id="root">
    <ul>
        <li>
            <a href="">
                <img src="" alt="">
            </a>
        </li>
        <li>
            <span></span>
        </li>
        <li>
        </li>
    </ul>
    <p></p>
    <button></button>
</div>

第一个参数是需要遍历的节点,第二个是节点所存储的数组,并且返回遍历完之后的数组,
该数组的元素顺序就是遍历顺序,调用方法:
let root = document.getElementById('root')
deepTraversal(root,nodeList=[])

js实现该算法代码(递归版本):

function deepFirstSearch(node,nodeList) {  
    if (node) {    
        nodeList.push(node);    
        var children = node.children;    
        for (var i = 0; i < children.length; i++) 
        //每次递归的时候将 需要遍历的节点 和 节点所存储的数组传下去
        deepFirstSearch(children[i],nodeList);    
    }    
    return nodeList;  
} 

非递归版本:

function deepTraversal(node) {
   var nodes = [];
   if (node !=null){
     var stack = [];
     stack.push(node);
     while (stack.length !== 0){
       var item = stack.pop();
       nodes.push(item);
       var children = item.children;
       for (var i=children.length-1;i>=0;i--){
         stack.push(children[i])
       }
     }
   }
   return nodes;
 }

广度优先遍历

广度优先遍历,指的是从图的一个未遍历的节点出发,先遍历这个节点的相邻节点,再依次遍历每个相邻节点的相邻节点。
在这里插入图片描述

递归版本的BFS由于层级太深,会导致堆栈溢出:Maximum call stack size exceeded,但遍历的顺序依旧没有问题,可以在遍历过程中进行操作,不返回遍历数组即可。
非递归版本:

function breadthFirstSearch(node) {  
    var nodes = [];  
    if (node != null) {  
        var queue = [];  
        queue.unshift(node);  
        while (queue.length != 0) {  
            var item = queue.shift();  
            nodes.push(item);  
            var children = item.children;  
            for (var i = 0; i < children.length; i++)  
                queue.push(children[i]);  
        }  
    }  
    return nodes;  
}

102. 二叉树的层序遍历
在这里插入图片描述
代码如下:
BFS 遍历使用队列数据结构,BFS 的遍历结果是一个一维数组,无法区分每一层。层序遍历要求我们区分每一层,也就是返回一个二维数组。

var levelOrder = function(root) {
    if(root == null) return [];
    let queue = [];
    queue.push(root);
    while(queue.length !== 0){
            let node = queue.shift();
            if(node.left !== null){
              queue.push(node.left)
            }
            if(node.right !== null){
              queue.push(node.right)
            } 
    }
};
  • 我们需要稍微修改一下代码,在每一层遍历开始前,先记录队列中的结点数量 n(也就是这一层的结点数量),然后一口气处理完这一层的 n个结点。
  • 可以看到,在 while 循环的每一轮中,都是将当前层的所有结点出队列,再将下一层的所有结点入队列,这样就实现了层序遍历。
/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrder = function(root) {
    if(root == null) return [];
    let res = [];
    let queue = [];
    queue.push(root);
    while(queue.length !== 0){
    //在每一层遍历开始前,先记录队列中的结点数量 len(也就是这一层的结点数量),然后一口气处理完这一层的len个结点。
        let len = queue.length; 
        let level = [];
        for(let i =0;i<len;i++){    // 变量 i 无实际意义,只是为了循环 n 次
           let node = queue.shift();
           level.push(node.val);
            if(node.left !== null){
              queue.push(node.left)
            }
            if(node.right !== null){
              queue.push(node.right)
            } 
        }
        res.push(level);   
    }
    return res;
};

NC14 按之字形顺序打印二叉树
在这里插入图片描述
奇数层正序,偶数层反序

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function Print(pRoot)
{
    // write code here
    //边界条件
    if(pRoot == null) return [];
    let res = [];
    let queue = [];
    let floor = 1;  //记录层数
    queue.push(pRoot);
    while(queue.length !== 0){
      //在每一层遍历开始前,先记录队列中的结点数量 len(也就是这一层的结点数量),然后一口气处理完这一层的len个结点。
        let len = queue.length;
        let level = [];  //放置每一层Nederland节点数
        for(var i =0;i<len;i++){
            let node = queue.shift();
            level.push(node.val);
            if(node.left !== null){
                queue.push(node.left);
            }
            if(node.right !== null){
                queue.push(node.right);
            }
        }
        if(floor%2){
            res.push(level);
        }else{
            res.push(level.reverse())
        }
        floor++;
    }
    return res;
}
module.exports = {
    Print : Print
};
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值