【问题标题】:How to prevent infinite recursion loop如何防止无限递归循环
【发布时间】:2019-11-27 13:43:46
【问题描述】:

我似乎无法解决我的递归问题。所以我有这个 Version 对象,其中包含对它所依赖的其他版本对象的引用列表。

版本

{
  "id": "id1",
  "version": "1",
  "dependencies": [
    {
      "id": "id2"
    },
    {
      "id": "id3"
    }
  ]
}

当我检索这个对象时,我还必须检索它的依赖项以及依赖项的依赖项,直到最终结束,这看起来像这样

版本号

{
  "id": "id1",
  "version": "1",
  "dependencies": [
    {
      "id": "id2",
      "version": "2",
      "dependencies": [
        {
          "id": "id4",
          "version": "4",
          "dependencies": []
        }
      ]
    },
    {
      "id": "id3",
      "version": "3",
      "dependencies": []
    }
  ]
}

这是我检索版本的递归函数

public VersionDto getVersion(String id)
{
    //Retrieves from database
    Version version = versionDAO.getVersion(id);

    //Convert to Dto (basic fields)
    VersionDto versionDto = new VersionDto(version);

    //Recursivly retrieve dependencies 
    for (Map<String, String> dep : version.getDependencies()) {
        VersionDto dto = new VersionDto();

        //Recursive call
        dto = getVersion(dep.get("id"));
        versionDto.getDependencies().add(dto);
    }

    return versionDto;
}

但是,如果版本可能是嵌套依赖项之一的依赖项,例如 v1 -> v2 -> v4 -> v1 导致无限重复,我会遇到可能的无限循环问题。

知道我该如何解决和防止这个无限循环,以便如果版本都准备好更早发生,它应该跳过它?

编辑:使用全局列表的解决方案

public VersionDto getVersion(String id)
{

    //Check global list contains version
    if (visited.contains(id)) {
        return null;
    }

    visited.add(docId);

    //Retrieves from database
    Version version = versionDAO.getVersion(id);

    //Convert to Dto (basic fields)
    VersionDto versionDto = new VersionDto(version);

    //Recursivly retrieve dependencies 
    for (Map<String, String> dep : version.getDependencies()) {
        VersionDto dto = new VersionDto();

        //Recursive call
        dto = getVersion(dep.get("id"));
        if(dep!= null) {
        versionDto.getDependencies().add(dto);
        }
    }

    return versionDto;
}

【问题讨论】:

  • 简而言之:你要么必须标记已经访问过的节点,要么记录你已经访问过的节点。无论哪种情况,您都必须在遇到节点时检查您是否已经访问过它。
  • 你想要什么行为,具体来说?您的数据有一个循环,您的代码尽职尽责地遵循该循环。
  • 您应该拥有所有访问过的 VersionDto 的结构,并且只有在它们不在列表中时才添加它们。也许如果您添加有关数据结构的更多信息,我可以提供更多信息。
  • 在所有递归函数中,你应该有一个结束条件来避免stackoverflow。也许您可以保留一个临时结构来定义已探索的依赖项?

标签: java recursion infinite-recursion


【解决方案1】:

确保递归函数结束的最佳方法是设置一个或多个条件。您必须拥有一个,以确保它不会陷入无限循环。

我建议创建一个数组或列表,在其中存储所有已访问过的节点,因此在运行递归函数时,您可以知道您已经访问过一个节点,并且可以移动到另一个节点。

【讨论】:

  • 我首先通过每个节点传递了一个列表,该列表将跟踪在该路径中访问过的内容,该路径有效但仍有一些不必要的循环。然后我尝试了一个效果更好的全局列表,谢谢。
  • 太棒了!很高兴能帮上忙!
【解决方案2】:

希望这会有所帮助。

如果 v1 的依赖关系总是相同的,那么它就可以工作。

        dto = getVersion(dep.get("id"));
        //check if the versionDto contains the dependecy already then break the loop here
        versionDto.getDependencies().add(dto);```

【讨论】:

    【解决方案3】:

    使用 Jackson 库可以非常有效地解决无限递归循环问题。 Jackson 库会派上用场,尤其是当您使用 Hibernate/JPA 进行持久化时。即,@JsonManagedReference 和 @JsonBackReference 注释将适用于您的案例。

    您还没有显示您的 JPA 实体代码,所以我无法告诉您应该将这些注释放在哪里。但是,如何使用它们的一个很好的例子可以在

    http://springquay.blogspot.com/2016/01/new-approach-to-solve-json-recursive.html

    希望你觉得它有用!

    【讨论】:

    • 有趣,将不得不对此进行更多研究。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-06
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 2012-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多