JavaScript 深度優先遍歷 廣度優先遍歷 && DOM應用方法
阿新 • • 發佈:2018-12-18
深度優先遍歷的遞迴寫法
function deepTraversal(node) {
var nodes = [];
if (node != null) {
nodes.push(node);
var children = node.children;
for (var i = 0; i < children.length; i++)
deepTraversal(children[i]);
}
return nodes;
}
//完整演示 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> </body> <script> function deepTraversal(node) { var nodes = []; if (node != null) { nodes.push(node); var children = node.children; if(children){ for (var i = 0; i < children.length; i++) { children[i].name = i deepTraversal(children[i]); } } } return nodes; } const a = deepTraversal({ children: [ { children: [ { children: ['a3'] }, // { children: ['b3'] }, // { children: ['c3'] } ] }, { children: [ { children: ['d3'] }, // { children: ['e3'] }, // { children: ['f3'] } ] }, ] }) console.log(a,'a') </script> </html>
深度優先遍歷的非遞迴寫法
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; }
廣度優先遍歷的遞迴寫法:
報錯:Maximum call stack size exceeded(…)
function wideTraversal(node) {
var nodes = [];
var i = 0;
if (!(node == null)) {
nodes.push(node);
wideTraversal(node.nextElementSibling);
node = nodes[i++];
wideTraversal(node.firstElementChild);
}
return nodes;
}
廣度優先遍歷的非遞迴寫法
function wideTraversal(selectNode) {
var nodes = [];
if (selectNode != null) {
var queue = [];
queue.unshift(selectNode);
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;
}
無向圖的深度和廣度優先遍歷(javascript)
function Graph(v){ //Graph類的定義
this.vertices=v;
this.edges=0; //邊的條數
this.adj=[]; //是一個二維陣列,行是頂點資訊,列是該頂點響鈴頂點資訊
for(var i=0;i<this.vertices;i++){
this.adj[i] =[];
this.adj[i].push("");
}
this.addEdge = addEdge; //新增邊
this.showGraph = showGroph; //列印所有頂點和相鄰頂點的列表
this.DepthFirstTravel = DepthFirstTravel; //深度遍歷
this.BreadthFirstTravel = BreadthFirstTravel;//廣度遍歷
this.marked=[]; //儲存所有已經訪問過的節點
for(var i=0;i<this.vertices;++i){
this.marked[i]=false; //false表示未訪問
}
}
function addEdge(v,w){
this.adj[v].push(w);
this.adj[w].push(v);
this.edges++;
}
function showGraph(){
for(var i=0;i<this.vertices;++i){
console.log(i+" -> ");
for(var j=0;j<this.vertices[i].length;++j){
console.log(this.adj[i][j]+ " ");
}
console.log("<br/>");
}
}
function DepthFirstTravel(v){ //深度遍歷
this.maked[v]=true;
console.log(v);
for(var w of this.adj[v]){
if(!this.marked[w]){
this.DepthFirstTravel(w);
}
}
}
function BreadthFirstTravel(v){ //廣度遍歷
var queue=[];
this.marked[v]=true;
queue.push(v);
while(queue.length>0){
var v=queue.shift();
console.log(v);
for(var w of this.adj[v]){
if(!this.marked[w]){
this.marked[w]=true
queue.push(w);
}
}
}
}
DOM中BFS(廣度優先遍歷)和DFS(深度優先遍歷)的方法
廣度優先遍歷,即父層遍歷結束,才開始遍歷子層,然後一直往下遍歷,如果是下面這樣一顆DOM樹
<div class="root">
<div class="container">
<section class="sidebar">
<ul class="menu"></ul>
</section>
<section class="main">
<article class="post"></article>
<p class="copyright"></p>
</section>
</div>
</div>
則需要遍歷為
DIV .root
DIV .container
SECTION .sidebar
SECTION .main
UL .menu
ARTICLE .post
P .copyright
這種形式,平級的子元素顯示在一起,並且最好隔開,這樣更容易理解。下面就開始寫BFS的實現方法。
首先需要一個列印函式,便於列印資訊
let printInfo = (node) => {
console.log(node.tagName, '.' + node.className)
然後是遍歷函式,遍歷中需要一箇中間陣列,即父層遍歷時每遍歷一個元素即將此元素的子元素寫入中間陣列,遍歷完之後,如果此陣列長度不為0,則接著遍歷下一層,直至最後一層。
// root為你需要遍歷的根節點,此處為.root
let root = document.getElementsByClassName('root')[0]
// 此時遍歷的為current,記錄下一層遍歷的為nextRound,初始值為root
let current = []
let nextRound = [root]
// 遍歷函式
function bfs () {
current = nextRound
// 將nextRound重置,切記不可直接設定length為0,這樣current也會重置
nextRound = []
Array.from(current).forEach(function (el) {
printInfo(el)
Array.from(el.children).forEach(function (element) {
nextRound.push(element)
})
})
}
// 開始遍歷
while(nextRound.length){
bfs()
}
深度優先遍歷以深度為主,即遍歷完某一個節點之後,才會繼續往下遍歷兄弟節點,這個只需要迴圈遍歷就行了。
function dfs (node) {
printInfo(node)
if(node.children.length){
Array.from(node.children).forEach(function (el) {
dfs(el)
})
}
}
dfs(root)
這樣打印出來的就是
DIV .root
DIV .container
SECTION .sidebar
UL .menu
SECTION .main
ARTICLE .post
P .copyright
還有一點就是childNodes和children這兩個時不太一樣的,childNodes會將文字節點也打印出來,這時候你就會看到很多undefined .undefined
這樣的東西,所以儘量使用children,然後用Array.from將其從HTMLCollection變為一個真正的陣列。