实现深度遍历和广度遍历(递归与非递归版本)

先画个树,而后解释 何为深度, 何为广度html

第一层  子集
                                    |
                        __________________________
                        |                        |
                第二层1 子集             第二层2 子集       
                        |                        | 
                -----------------
                第三层11,子集       第三层12   
                         |
                    第四层111

图就不画太复杂了,最高四层的结构,若是换成html的形式的话能够理解成node

<div>------第一层
    <ul>----------第二层1
        <li> -----------第三层 11
            <span></span> -----------第四层 111
        </li>
        
        <li>---------------第三层 12
        </li>
    </ul>
    
    <p></p> ------------第一层2
<div>

深度遍历,就是 从 第一层开始 -》 1 -》 11 -》111 -》 12 -》 2
这个意思就是,若是有下一级优先探索下一级的,没有了话,再去探索兄弟层级(以此类推)
就是作一道菜,须要菜和调料,调料是须要调制的,好比调料须要鸡汁和糖,鸡汁又须要调制,那么 正常流程 就是 ,
一、开始作菜 -》 开始调料 -》 鸡汁 -》调制鸡汁的材料
二、等这些弄完了,再去加糖 ,完成调料步骤
三、糖加完了,再去切菜,完成作菜步骤
这个就是一个深度的过程算法

而广度遍历则相反, 顺序应该是 -> 1-> 2 -> 11 -> 12 -> 111
意思就是有兄弟层级优先解析兄弟层级,而后解析下一层级数组

广度比较符合正常人的思惟,就像复习的时候,
1.先把整本书捋一遍,而后画重点,
2.捋完以后看重点,重点内容里面有一些具体时间,再整理出来,
3.最后重点背诵时间
广度遍历须要手动去终结(判断还有没有整理内容了)spa

根据js单线程的原理,深度很好实现,由于循环递归默认就是深度遍历
把刚刚的图 写成一个数组线程

const arr = [
     {
         name: '1',
         childrens: [
             {
                 name: '11',
                 childrens: [
                     {
                         name: '111'
                     }
                 ]
             },

             {
                 name: '12'
             }
         ]
     },

     {
         name: '2'
     }
]

我多加了一些换行,方便看清楚code

深度遍历htm

function check(nodeArr) {
    nodeArr.forEach(node => {
        console.log(node.name)
        if(node.childrens) {
            check(node.childrens)
        }
    })
}
check(arr) //
1
11
111
12
2

这段代码很好理解,若是有子集,将子集和父集作一样处理,或者说,做为一个新的参数给check这个方法。递归

广度遍历
广度遍历的话须要一个容器去记录子集,等此层级的兄弟集处理完成,再去处理子集,子集的处理也以此类推
先上代码io

function checkN(nodeX) {
    var node_ = []; // 用来存储子集
    nodeX.forEach(node => {
        console.log(node.name);
        if(node.childrens) {
            node_ = [...node_, ...node.childrens];
        }
    })
    if(node_[0])
        checkN(node_);
}
checkN(arr) //
1
2
11
12
111

具体内容就这些了,这两个算法我刚刚本身想着写的,不知道和一些比较正式的文章算法是否是略有出入,我也懒得去看了

应一个大佬朋友,也是我高中同窗的要求,写了一个非递归版本

这个是深度优先的.....

function check_(nodeArr) {
     let processList = nodeArr;
     while(processList[0]) {
         const a = processList.shift();
         if(a.childrens) 
             processList = [...a.childrens, ...processList];
         console.log(a.name);        
     }
 }
 check_(arr);// 
1
11
111
12
2

这个是广度优先的

function checkX_(nodeArr) {
     let processList = nodeArr;
     while(processList[0]) {
         const a = processList.shift();
         if(a.childrens) {
             processList = [...processList,...a.childrens];
         }
             console.log(a.name);        
     }
 }

checkX_(arr);// 
1
2
11
12
111

这两个代码的类似度几乎是百分之九十,惟一的区别就是先进先出(广度优先),和先进后出(深度优先)

先进先出的话,后来者就排到其后面,先进后出,后来者就排到其前面那么惟一的区别就是 processList = [...a.childrens, ...processList]; 仍是 processList = [...processList,...a.childrens];

相关文章
相关标签/搜索