1. 程式人生 > >JavaScript 深度優先遍歷 廣度優先遍歷 && DOM應用方法

JavaScript 深度優先遍歷 廣度優先遍歷 && DOM應用方法

深度優先遍歷的遞迴寫法

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變為一個真正的陣列。