深度优先遍历的递归写法
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变为一个真正的数组。