<!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);
}
}
}
//广度优先遍历的非递归写法,遍历到k-1层,适用于限定遍历到第几层的情况,同时可以获取第k层的节点数量
function BFT(root,fVistor,k) {
fVistor = fVistor || console.log;
if (root != null) {
//兼容root为数组情况
var queue = [].concat(root);
var level = 1;
while (queue.length != 0) {
var levelSize = queue.length;
if(level == k){
return levelSize; //可以获取第k层的节点数量,同时遍历到第k-1层就停止遍历
}
while(levelSize > 0){
var item = queue.shift();
//找到就break,使得方法兼具广度优先搜索功能,找到就停止遍历
if(fVistor(item)) break;
if(item.children) queue.push(...item.children);
levelSize--;
}
level++;
}
}
}
</script>
</body>
</html>