一种链式删除算法的实现

179 阅读3分钟

背景

这两天在做一个需求,用户可以选择一个表和前一个表进行关联,同时也可以删除某个表,但是删除表的时候需要将其后面的关联关系也删除, 由此引申出了这个问题,如何删除一个表后,将其后面的关联关系也删除,这里我们采用链式删除的方式,递归删除后面的关联关系,最后再从映射中生成新的数据数组。

链式删除算法的思路

算法的基本思路是将数据表示为一个图的形式,在图中,每个 table1 是一个节点,而 table2 是它的邻居节点。通过图的遍历和递归删除,我们可以确保目标节点及其所有后继节点都被删除。

具体步骤如下:

  1. 构建图结构: 将数据集转化为一个图结构,使用 Map 来表示这个图。Map 的键是 table1,值是与其关联的 table2 集合。这样,图中每个节点都指向一个集合,表示它的所有邻居。
  2. 递归删除关联节点: 针对目标节点,递归删除与之相关的所有节点。每当删除一个节点时,还需要删除它指向的所有其他节点,直到整个关联链条被清除。
  3. 生成新的数据集合: 通过过滤掉已经删除的节点,最终返回一个新的数据集合。新集合仅包含那些没有被删除的节点。

代码实现

export const filteredAssociation2 = (data: { table1: number; table2: number }[], target: number): { table1: number; table2: number }[] => {
  // 创建一个映射来存储关联关系
  const map = new Map<number, Set<number>>();

  // 将数据转换为图的形式
  data.forEach(({ table1, table2 }) => {
    if (!map.has(table1)) map.set(table1, new Set());
    map.get(table1)?.add(table2);
  });

  // 递归删除向后关联
  function removeLinks(node: number) {
    if (!map.has(node)) return;
    const nexts = map.get(node);
    nexts?.forEach((next) => {
      removeLinks(next);
      map.delete(node);
    });
  }

  // 删除目标节点及其关联
  removeLinks(target);

  // 删除目标节点的所有关联
  map.forEach((value) => {
    value.delete(target);
  });

  // 从映射生成新的数据数组
  const result: { table1: number; table2: number }[] = [];
  map.forEach((value, table1) => {
    if (value.size) {
      value.forEach((table2) => {
        result.push({ table1, table2 });
      });
    }
  });

  // 返回过滤后的数据
  return data.filter(({ table1, table2 }) => result.some((item) => item.table1 === table1 && item.table2 === table2));
};

解释

  • 数据转换为图结构: 数据集通过 Map 转换为图的形式,其中每个 table1 都对应一个 Set,集合中包含与之关联的所有 table2。这样,Map 实际上构建了一个邻接表。
  • 递归删除removeLinks 函数是核心的递归删除函数。它会从目标节点开始,递归删除与该节点关联的所有后继节点。每删除一个节点,就从图中移除该节点及其对应的关联。
  • 生成结果数据: 在删除操作完成后,我们遍历图中的所有节点,生成新的数据集合。此时,数据中只保留那些没有被删除的关联。
  • 返回结果: 最终,算法会过滤出原始数据中那些没有涉及目标节点删除操作的关联记录。

示例

假设有以下关联数据:

const data = [
  { table1: 1, table2: 2 },
  { table1: 1, table2: 3 },
  { table1: 2, table2: 4 },
  { table1: 3, table2: 4 },
  { table1: 4, table2: 5 },
];

const target = 2; // 我们希望删除与table2=2相关的所有记录

执行 filteredAssociation2(data, target) 后,目标 table2 = 2 及其关联的节点将被删除,返回的数据将不再包含任何与 table2 = 2 或后继节点有关的记录。

应用场景

链式删除算法适用于各种需要清理关联关系的场景,如:

  • 社交网络:删除某个用户及其所有相关联的好友或内容。
  • 任务依赖:删除某个任务及其依赖的所有子任务。
  • 数据库关联:删除某条记录及其所有外键关联的记录。

最后

这只是我的一种实现方式,你可以根据自己的需求来实现这个功能,如果你有更好的实现方式,欢迎在评论区留言分享给大家。