深度优先遍历(Depth First Search, 简称 DFS) 与广度优先遍历(Breath First Search)是图论中两种非常重要的算法,生产上广泛用于拓扑排序,寻路(走迷宫),搜索引擎,爬虫等,也频繁出现在 leetcode,高频面试题中。
1.深度优先遍历
1-1.递归实现
主要思路是从图中一个未访问的顶点 V 开始,沿着一条路一直走到底,然后从这条路尽头的节点回退到上一个节点(看该节点 是否还有除该子节点以外的节点,没有继续回退到父节点,有则遍历该子节点之外的其他节点),再从另一条路开始走到底…,不断递归重复此过程,直到所有的顶点都遍历完成,它的特点是不撞南墙不回头,先走完一条路,再换一条路继续走。
递归的表达性很好,也很容易理解,不过如果层级过深,很容易导致栈溢出。
以上的遍历是树的前序遍历,实际上不管是前序遍历,还是中序遍历,亦或是后序遍历,都属于深度优先遍历。
<div id="root">
<ul>
<li>
<a href="">
<img src="" alt="">
</a>
</li>
<li>
<span></span>
</li>
<li>
</li>
</ul>
<p></p>
<button></button>
</div>
// 1-1方法一:递归方式
function deepFirstSearch(node, nodeList) {
if (node) {
nodeList.push(node);
var children = node.children;
for (var i = 0; i < children.length; i++)
//每次递归的时候将 需要遍历的节点 和 节点所存储的数组nodeList传下去
deepFirstSearch(children[i], nodeList);
}
return nodeList;
}
let root = document.getElementById('root')
var nodeList = deepFirstSearch(root, [])
console.log(nodeList);
1-2.非递归实现
对二叉树来说,由于是先序遍历(先遍历当前节点,再遍历左节点,再遍历右节点),所以我们有如下思路:
对于每个节点来说,先遍历当前节点(将当前节点弹栈),然后把右节点压栈,再压左节点(这样弹栈的时候会先拿到左节点遍历,符合深度优先遍历要求)。
弹栈,拿到栈顶的节点,如果节点不为空,重复步骤 1, 如果为空,结束遍历。
// 1-2方法二:非递归方式
function deepFirstSearch(node) {
var nodeList = []; //下方存放弹栈节点的容器
if (node != null) {
var stack = []; //上方栈结构
stack.push(node);
while (stack.length != 0) {
var item = stack.pop(); // 出栈,先弹出左边的子节点
nodeList.push(item);
var children = item.children;
for (var i = children.length - 1; i >= 0; i--)
// 入栈顺序为:子节点从右向左入栈
stack.push(children[i]);
}
}
/* 将最终遍历结果存放在nodeList数组中。*/
return nodeList;
}
let root = document.getElementById('root')
var nodeList = deepFirstSearch(root)
console.log(nodeList);
不用担心递归那样层级过深导致的栈溢出问题
2.广度优先遍历
广度优先遍历,指的是从图的一个未遍历的节点出发,先遍历这个节点的相邻节点,再依次遍历每个相邻节点的相邻节点。
广度优先遍历也叫层序遍历
深度优先遍历用的是栈,栈对数组尾部进行操作;而广度优先遍历要用队列来实现,队列对数组首部进行操作。
<script>
// 1-2方法二:非递归方式
function breadthFirstSearch(node) {
var nodeList = [];
if (node != null) {
var queue = [];
queue.unshift(node); //进入队列
while (queue.length != 0) {
var item = queue.shift(); //离开队列
nodeList.push(item);
var children = item.children;
for (var i = 0; i < children.length; i++)
// 依次将该层的子元素放到队列中
queue.push(children[i]);
}
}
/* 将最终遍历结果存放在nodeList数组中。*/
return nodeList;
}
let root = document.getElementById('root')
var nodeList = breadthFirstSearch(root)
console.log(nodeList);
</script>
https://developer.51cto.com/art/202004/614590.htm
https://segmentfault.com/a/1190000018706578