實現深度遍歷和廣度遍歷(遞歸與非遞歸版本)

先畫個樹,而後解釋 何爲深度, 何爲廣度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];

相關文章
相關標籤/搜索