[题图无关,仅以此纪念我们逝去的青春]
虽然已经离开学校多年,但相信很多小伙伴对DFS和BFS这两个词还不算陌生。
由于我们前端日常开发中需要算法编程的场景其实不多,所以前端同学更有必要额外花点时间温习和巩固。
一来是因为现在外面都流行面试造航母,数据结构和算法基本大厂必考;二来是这东西也是咱程序员安身立命的基础,你可以不用,但是不能不懂。
下面,我就尝试用最简单易懂的语言和案例,跟大家一起回顾一下前端面试中最高频出现的两个算法:DFS
和 BFS
。
假设有一棵树,它的结构长这样:
js
// 示例树
// 1
// / | \
// 2 3 4
// /| \
// 5 6 7
我们以这个实例树为基础,分别演示和讲解这两种算法的原理。
DFS:深度优先搜索
【深度优先搜索】顾名思义就是搜索时永远以"刨根问底",直到把当前路径走到头再返回上一层继续以深度优先的原则去搜索。
代码示例:
js
// 定义树节点构建方法
function TreeNode(val) {
this.val = val;
this.children = [];
}
// 创建一个示例树
const root = new TreeNode(1);
root.children.push(new TreeNode(2), new TreeNode(3), new TreeNode(4));
root.children[0].children.push(new TreeNode(5), new TreeNode(6));
root.children[1].children.push(new TreeNode(7));
// DFS函数
function dfs(node) {
if (node == null) return;
console.log(node.val); // 访问当前节点的值
// 遍历所有子节点
for (let child of node.children) {
dfs(child); // 递归调用DFS
}
}
// 执行DFS遍历
dfs(root);
// 依次打印
// 1
// 2
// 5
// 6
// 3
// 7
// 4
在这个例子中,我们首先定义了一个TreeNode
类,用于创建树节点。每个节点有一个值val
和一个子节点数组children
。
然后,我们定义了一个dfs
函数,它接受一个节点作为参数。如果节点不为空,它会打印节点的值,然后递归地对每个子节点调用dfs
函数,从而实现深度优先遍历。
最后,我们创建了一个简单的树结构,并调用dfs
函数来遍历它。在控制台中,你将看到按深度优先顺序打印的节点值。
BFS:广度优先搜索
【广度优先搜索】顾名思义就是搜索时永远把当前层级的节点都遍历到,再查找下一层级,一层层查找直到最后一层。
代码示例:
js
// 定义树节点构建方法
function TreeNode(val) {
this.val = val;
this.children = [];
}
// 创建一个示例树
const root = new TreeNode(1);
root.children.push(new TreeNode(2), new TreeNode(3), new TreeNode(4));
root.children[0].children.push(new TreeNode(5), new TreeNode(6));
root.children[1].children.push(new TreeNode(7));
function bfs(root) {
if (!root) return; // 如果根节点为空,则直接返回
const queue = []; // 创建一个队列
queue.push(root); // 将根节点入队
while (queue.length > 0) { // 当队列不为空时,继续遍历
const node = queue.shift(); // 取出队列的第一个节点
console.log(node.val); // 打印当前节点的值
// 将当前节点的所有子节点入队
for (const child of node.children) {
queue.push(child);
}
}
}
// 执行BFS遍历
bfs(root);
// 依次打印
// 1
// 2
// 3
// 4
// 5
// 6
// 7
这段代码将会按照广度优先的顺序遍历给定的树结构,并打印出每个节点的值。遍历的顺序将是:1, 2, 3, 4, 5, 6, 7。
篇幅有限,本文也只是浅尝辄止,从原理上大概的讲解了下DFS和BFS,算是勉强应付面试的入门篇。
如果对此感兴趣,想系统学习、掌握数据结构和算法,可以看这里。