<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>深度遍歷和廣度遍歷測試</title> <style type="text/css"> </style> </head> <body> <div class="box"> <ul class="menus"> <li class="item1"><i class="item1-icon"></i><span class="item1-content">菜單1</span></li> <li class="item2"><i class="item2-icon"></i><span class="item2-content">菜單2</span></li> <li class="item3"><i class="item3-icon"></i><span class="item3-content">菜單3</span></li> </ul> </div> <script> console.log('深度優先遞歸'); DFTRecur(document.body,[],function(item){ console.log(item); }); console.log('深度優先非遞歸'); let res = DFT(Array.from(document.body.children),function(item){ // if(item.className == 'item2-content'){ // console.log('taget item', item); // return true; // } console.log(item); }); console.log('廣度優先遞歸'); BFTRec(document.body,[]); console.log('廣度優先非遞歸'); BFT(Array.from(document.body.children)); //深度優先搜索的遞歸寫法 function DFSRecur(root,stack,fVistor) { let b = false; if (root != null) { stack.push(root); //函數fVistor,節點傳入函數,節點一旦滿足某種條件,就返回true //可以在找到第一個滿足條件的節點后,就停止遍歷 if(fVistor(root))return true; var children = root.children; if(children){ for (var i = 0; i < children.length; i++){ b = DFTRecur(children[i],stack,fVistor); //有一個子節點滿足條件就停止循環 if(b) break; } } //當前節點及其子節點都不滿足條件就出棧 if(!b) stack.pop(); } return b; } //深度優先遍歷的遞歸寫法,深度優先遍歷遞歸,不需要使用棧,通常是使用先序遍歷,即先遍歷根節點,再遍歷所有子節點 function DFSRecur(root,stack,fVistor) { if (root != null) { fVistor(root) var children = root.children; if(children){ for (var i = 0; i < children.length; i++){ DFTRecur(children[i],stack,fVistor); } } } } //深度優先遍歷的非遞歸寫法 function DFT(root,fVistor) { fVistor = fVistor || console.log; if (root != null) { //兼容root為數組,且從前往后深度遍歷 var stack = [].concat(root).reverse(); while (stack.length != 0) { var item = stack.pop(); //滿足條件就break,使得方法兼具深度優先搜索的功能,找到就跳出循環,停止查找 if(fVistor(item)) break;if(item.children) stack.push(...Array.from(item.children).reverse()); } } } //廣度優先遍歷的遞歸寫法,廣度優先的遞歸和非遞歸寫法都需要隊列 function BFTRec(root,queue,fVistor){ fVistor = fVistor || console.log; if(root != null){ queue.push(root); //滿足條件return,使該方法兼具廣度優先搜索的功能,找到就停止遍歷 if(fVistor(root)) return; //先訪問下一個兄弟節點,遞歸會一直橫向訪問,直至橫向訪問完畢 BFTRec(root.nextElementSibling,queue,fVistor); //回到本行的第一個節點root root = queue.shift(); //跳到root節點的下一行的第一個節點,又會開始橫向遍歷 BFTRec(root.firstElementChild,queue,fVistor); } } //廣度優先遍歷的非遞歸寫法 function BFT(root,fVistor) { fVistor = fVistor || console.log; if (root != null) { //兼容root為數組情況 var queue = [].concat(root); while (queue.length != 0) { var item = queue.shift(); //找到就break,使得方法兼具廣度優先搜索功能,找到就停止遍歷 if(fVistor(item)) break; if(item.children) queue.push(...item.children); } } } </script> </body> </html>