推荐用 set 而不是数组或普通对象:数组 includes() 为 o(n) 易拖慢性能;普通对象存在类型转换冲突且不支持对象/symbol/null;set 支持任意值唯一性判断,语义清晰、无副作用。

在图论算法(如 DFS、BFS)中,用 Set 管理已访问节点是最常用且高效的方式——它提供 O(1) 平均时间复杂度的查找和插入,比数组 includes()(O(n))或对象键查重(需处理类型/字符串转换)更可靠、更简洁。
为什么推荐用 Set 而不是数组或普通对象?
数组:每次检查是否已访问都要遍历,BFS/DFS 中频繁调用会显著拖慢性能;普通对象(如 {nodeId: true})虽快,但存在隐式类型转换风险(如 visited[0] 和 visited['0'] 冲突),且无法安全存储对象、Symbol 或 null 作为节点标识。
而 Set 原生支持任意值(包括对象、数字、字符串、Symbol)的唯一性判断,语义清晰、无副作用。
基础用法:初始化、检查、添加
以邻接表表示的图为例(节点为数字):
const visited = new Set();
const queue = [0]; // BFS 起始节点
while (queue.length > 0) {
const node = queue.shift();
if (visited.has(node)) continue; // 已访问,跳过
visited.add(node); // 标记为已访问
// 处理当前节点逻辑(如收集结果、更新距离等)
for (const neighbor of graph[node]) {
if (!visited.has(neighbor)) {
queue.push(neighbor);
}
}
}
处理非原始类型节点(如对象节点)
若图节点是对象(例如 {id: 1, name: 'A'}),直接用 Set 仍有效——因为 Set 使用 SameValueZero 比较,对象按引用判断:
- ✅ 正确:同一对象实例多次加入,
Set自动去重 - ⚠️ 注意:不同对象即使属性相同,也被视为不同节点(符合图论中“节点是实体”的直觉)
- ? 若需按 ID 逻辑去重(忽略对象差异),可统一用
node.id字符串作为 key 存入Set,而非对象本身
常见优化与注意事项
- 避免在循环内重复创建
Set:应在外层初始化一次,供整个搜索过程复用 - 不需要手动清空:每次新搜索前重新
new Set()即可,轻量无负担 - 调试时可用
[...visited]快速转为数组查看内容 - 不建议用
visited.size === 0判断是否为空——直接用visited.size或visited.values().next().done更准确(不过通常没必要)











