You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何array.splice与array.filter实现removeEdge会导致removeVertex结果不同?

问题原因分析

这种差异的核心在于splice和filter操作数组的本质不同,结合removeVertex的遍历逻辑,导致部分边未被正确删除:

1. 两种removeEdge实现的本质区别

  • splice版本:原地修改数组
    splice会直接修改原数组的内容和长度,比如执行this.adjacencyList[v2].splice(idx2, 1)时,会直接从原数组中删除元素,数组长度实时缩短。
  • filter版本:返回新数组
    filter不会修改原数组,而是生成一个过滤后的新数组再赋值给原邻接表变量,原数组在遍历过程中不会被改动。

2. 遍历逻辑与数组修改的冲突

假设你的removeVertex使用了正向for循环(依赖数组实时长度)遍历待删除顶点的邻接表,比如:

removeVertex(vertex) {
  for (let i = 0; i < this.adjacencyList[vertex].length; i++) {
    const adjacent = this.adjacencyList[vertex][i];
    this.removeEdge(adjacent, vertex);
  }
  delete this.adjacencyList[vertex];
}

当调用splice版removeEdge时,会触发双向删除:不仅删除邻接顶点(比如Dallas)的邻接表中的目标顶点(Hong Kong),还会删除目标顶点(Hong Kong)的邻接表中的邻接顶点(Dallas)。这会导致目标顶点的邻接表长度实时缩短,循环条件i < this.adjacencyList[vertex].length提前不满足,部分邻接顶点会被跳过遍历,它们的邻接表自然残留目标顶点。

举个具体流程:

  • 初始Hong Kong的邻接表:['Dallas', 'Tokyo']
  • i=0,处理Dallas:调用splice版removeEdge,删除Dallas邻接表中的Hong Kong,同时删除Hong Kong邻接表中的Dallas,此时Hong Kong的邻接表变为['Tokyo'],长度为1
  • i递增到1,此时i < 1不成立,循环终止,Tokyo未被处理,Tokyo的邻接表仍保留Hong Kong(核心逻辑适用于你遇到的Dallas残留场景)

而filter版removeEdge在处理时,不会修改原邻接表数组(只是赋值新数组),removeVertex的for循环会基于初始数组长度遍历所有邻接顶点,所有对应的边都会被正确删除。

3. 解决方案

  • 若坚持用splice版removeEdge:修改removeVertex的遍历逻辑,遍历邻接表的副本,或者用反向for循环(从后往前遍历,避免数组缩短导致的元素跳过):
    // 遍历副本
    const adjacentVertices = [...this.adjacencyList[vertex]];
    adjacentVertices.forEach(adjacent => this.removeEdge(adjacent, vertex));
    
    // 或反向for循环
    for (let i = this.adjacencyList[vertex].length - 1; i >= 0; i--) {
      const adjacent = this.adjacencyList[vertex][i];
      this.removeEdge(adjacent, vertex);
    }
    
  • 继续使用filter版removeEdge:逻辑更简洁,不会出现遍历冲突问题,唯一的小缺点是会创建新数组,但对于图的场景来说影响可以忽略。

内容的提问来源于stack exchange,提问作者R41313IT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 09:22:54