当前位置: 首页 > 知识库问答 >
问题:

在所有递归调用从调用堆栈弹出之前返回最终结果的递归函数

楮景明
2023-03-14

我很困惑为什么我写的这个DFS算法没有访问我图中的最终顶点。下面是代码:

图/顶点类

import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;

public class Graph {

    private HashMap<Vertex, ArrayList<Vertex>> adjacencyList;

    public Graph() {
        this.adjacencyList = new HashMap<>();
    }

    public void addVertex(Vertex vertex) {
        if (!adjacencyList.containsKey(vertex)) {
            adjacencyList.put(vertex, new ArrayList<>());
        }
    }

    public void addEdge(Vertex vertex1, Vertex vertex2) {
        this.adjacencyList.get(vertex1).add(vertex2);
        this.adjacencyList.get(vertex2).add(vertex1);
    }

    public HashMap<Vertex, ArrayList<Vertex>> getAdjacencyList() {
        return adjacencyList;
    }

    public void printAdjacencyList(Vertex vertex) {
        System.out.print(vertex.getValue() + ": ");
        for (Vertex v : adjacencyList.get(vertex)) {
            System.out.print(v.getValue());
        }
        System.out.println();
    }

    public ArrayList<Vertex> DFS_Recursive(Vertex start) {
        ArrayList<Vertex> result = new ArrayList<>();
        HashMap<Vertex, Boolean> visited = new HashMap<>();
        for (Vertex v : adjacencyList.keySet()) {
            visited.put(v, false);
        }
        return DFS_Recursive_Utility(start, result, visited);
    }

    private ArrayList<Vertex> DFS_Recursive_Utility(Vertex vertex, ArrayList<Vertex> results, HashMap<Vertex, Boolean> visited) {
        if (vertex == null) {
            return null;
        }
        visited.put(vertex, true);
        results.add(vertex);
        for (Vertex v : adjacencyList.get(vertex)) {
            if (!visited.get(v)) {
                return DFS_Recursive_Utility(v, results, visited);
            }
        }
        return results;
    }
}

class Vertex<E> {

    private E value;

    public Vertex(E value) {
        this.value = value;
    }

    public E getValue() {
        return value;
    }
}

主类

public static void main(String[] args) {

    Vertex<String> a = new Vertex<>("A");
    Vertex<String> b = new Vertex<>("B");
    Vertex<String> c = new Vertex<>("C");
    Vertex<String> d = new Vertex<>("D");
    Vertex<String> e = new Vertex<>("E");
    Vertex<String> f = new Vertex<>("F");

    Graph graph = new Graph();
    graph.addVertex(a);
    graph.addVertex(b);
    graph.addVertex(c);
    graph.addVertex(d);
    graph.addVertex(e);
    graph.addVertex(f);
    graph.addEdge(a, b);
    graph.addEdge(a, c);
    graph.addEdge(b, d);
    graph.addEdge(c, e);
    graph.addEdge(d, e);
    graph.addEdge(d, f);
    graph.addEdge(e, f);
    System.out.println();
    for (Vertex v : graph.getAdjacencyList().keySet()) {
        graph.printAdjacencyList(v);
    }
    System.out.println();
    for (Vertex v : graph.DFS_Recursive(a)) {
        System.out.print(v.getValue() + " ");
    }
}

调用DFS_Recursive()的结果是:

A B D E C 

我已经使用了IntelliJ调试器,当算法到达顶点C时,堆栈上仍然有剩余的调用,以便它检查E的邻接列表中任何剩余的未访问顶点。然而,在这一点上,它只返回结果ArrayList,其余的递归调用被忽略。

有没有关于发生了什么以及如何修复的想法?

共有1个答案

梁俊智
2023-03-14

据我所知,您的实现返回得太早,以至于填充顶点列表无法正确填充。如下所示更改实现。

public ArrayList<Vertex> DFS_Recursive(Vertex start) {
    ArrayList<Vertex> result = new ArrayList<>();
    HashMap<Vertex, Boolean> visited = new HashMap<>();
    for (Vertex v : adjacencyList.keySet()) {
        visited.put(v, false);
    }
    DFS_Recursive_Utility(start, result, visited);
    return result;
}


private void DFS_Recursive_Utility(Vertex vertex,
                                   ArrayList<Vertex> results,
                                   HashMap<Vertex, Boolean> visited) {
        if (vertex == null) {
            return;
        }
        visited.put(vertex, true);
        results.add(vertex);
        for (Vertex v : adjacencyList.get(vertex)) {
            if (!visited.get(v)) {
            DFS_Recursive_Utility(v, results, visited);
        }
    }
}
 类似资料:
  • 我是一名大学生,学习球拍/方案和C作为我的CS学位的入门课程。 我在网上读到,在C语言中使用迭代而不是递归通常是最佳实践,因为递归由于将堆栈帧保存到调用堆栈上而代价高昂。。。 现在,在类似于Scheme的函数式语言中,递归一直在使用。我知道尾部递归在Scheme中是一个巨大的优势,据我所知,它只需要一个堆栈帧(有人能澄清这一点吗?)无论递归有多深。 我的问题是:非尾递归呢?每个函数应用程序是否保存

  • 问题内容: 我可以在变量中创建一个递归函数,如下所示: 这样,将输出 。假设我做了以下事情: 将输出 如上。如果我再更改如下: 然后将给出,如预期的那样。 现在给出 它所指的,而不是函数(它本身指向的)。在某些情况下这可能是理想的,但是有没有一种方法可以编写函数以便它调用自身而不是保存它的变量? 也就是说,是否可以 仅 更改线路,以便 在调用时仍能完成所有这些步骤?我试过了,但这给了我错误。 问题

  • 让我们回到函数,进行更深入的研究。 我们的第一个主题是 递归(recursion)。 如果你不是刚接触编程,那么你可能已经很熟悉它了,那么你可以跳过这一章。 递归是一种编程模式,在一个任务可以自然地拆分成多个相同类型但更简单的任务的情况下非常有用。或者,在一个任务可以简化为一个简单的行为加上该任务的一个更简单的变体的时候可以使用。或者,就像我们很快会看到的那样,处理某些数据结构。 当一个函数解决一

  • 问题内容: 我有一个异步函数,要连续多次调用。问题是“多个”可以是几十万或数百万… 显而易见的方法是从回调中调用相同的函数,如下所示: 当然,涉及一些逻辑来停止递归。问题是堆栈是否充满了调用,并可能在某些时候导致堆栈溢出? 问题答案: 问题是堆栈是否充满了调用,并可能在某些时候导致堆栈溢出? 否。 如果调用回调是异步传递的,则不会堆积堆栈。 在您的代码中: 这是逐步发生的事情: 首先被称为。 然后

  • 第二个构造函数应该调用第一个构造函数,但却给了我“递归构造函数调用”错误。 我明白这个错误的意思,只是不明白递归在哪里。第一个contructor将作为参数,而应该是该类型的数组。我错过了什么? 多谢了。