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()
}

深度优先遍历以深度为主,即遍历完某一个节点之后,才会继续往下遍历兄弟节点,这个只需要循环遍历就行了。

扫描二维码关注公众号,回复: 4557659 查看本文章
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变为一个真正的数组。

猜你喜欢

转载自blog.csdn.net/weixin_40222803/article/details/84989478