簡體   English   中英

Java-遞歸-線程“ main”中的異常java.lang.StackOverflowError

[英]Java - Recursion - Exception in thread “main” java.lang.StackOverflowError

嘗試打印出文件依賴項列表時遇到問題。

關於程序:

  1. 掃描給定的* .c文件以查找依賴關系,更具體地說,查找“ #include“%”
  2. 查找那些文件並遞歸掃描它們的依賴關系
  3. 所有信息都存儲在ConcurrentHashMap(key:String value:Linked List of Strings)theTable中,其中Linked List of Strings包含依賴項列表。
  4. 處理完某個文件后,我得到以下哈希表:

如果我了解地圖輸出的意思,則頭文件中會有一個循環(#include循環)。

i_50.h=[i_35.h, i_28.h, i_45.h, i_44.h, i_46.h],
....
i_35.h=[i_50.h, i_51.h]

這意味着您的依賴關系是圖形而不是DAG。 這又意味着簡單的遞歸遍歷將不起作用。

從外觀上看,您試圖進行圖遍歷,但是由於某種原因,您的循環檢測/避免無法正常工作,並且算法進入了“無限”遞歸。


看完代碼后,我想我可以看到問題出在哪里。 在第一種方法中,您檢查是否已經打印了一個依賴項,然后在alreadyPrinted映射中將該條目設置為已聲明。 但是你再繼續,不論打印。 然后,在第二種方法中,每次遞歸到第一種方法時,您(莫名其妙地)將創建一個新的alreadyPrinted地圖。 換句話說,避免循環的邏輯被打破了。


我建議您不要去研究自己喜歡的“數據結構和算法”教科書,而是在索引中查找“圖形遍歷”,而不是為您修改代碼。 另外,這是我在一些在線講義中找到的頁面:

Wikipedia和其他地方還涉及圖遍歷。 Google進行“ java遞歸圖遍歷”,並嘗試找到對您有意義的東西。

通用算法如下所示:

    traverse(Node node):
        traverse_0(node, new Set<Node>())

    traverse_0(Node node, Set<Node> visited):
        if (visited.contains(node)) 
            return
        visited.add(node)
        for (Node child: node.children) 
            traverse_o(child, visited)

測試依賴項是否已經打印的唯一地方是第一個for循環。 您也應該檢查第二個for循環!

for (String d : dependencies) {
    if (!alreadyPrinted.containsKey(d)) {
        LinkedList<String> key = theTable.get(d);           
        if (key != null)            
            output += printDependencies(theTable, key, alreadyPrinted);
    }
}

一旦某些依賴項看起來像這樣,就很容易看到您的算法會遞歸:

item:  ...., item, ....

(我聽到你說:“那不可能發生,因為...”。但是,SO表示確實發生了,或者堆棧太小了。)

順便說一句,您維護“已打印”地圖,但是沒有在哪里使用? 這暗示了您的實現中存在缺陷。

當您維護某種狀態(alreadyPrinted和輸出)時,我建議將狀態移至實例變量,並使用對象而不使用類方法。

問題是我的Graph遍歷有我沒有處理的循環。 下面提供了工作代碼。

private static String printDependencies(ConcurrentHashMap<String, LinkedList<String>> theTable, LinkedList<String> dependencies, ConcurrentHashMap<String, Boolean> alreadyPrinted) {

    String output = "";

    for (String d : dependencies) {
        boolean isPrinted = alreadyPrinted.containsKey(d);
        if (!isPrinted) {
            output += " " + d;
            alreadyPrinted.put(d, true);
        }           
    }

    for (String d : dependencies) {
        LinkedList<String> key = theTable.get(d);
        if (key != null) {
            LinkedList<String> unvisited = new LinkedList<String>();
            for (String filename : key)
                if (!alreadyPrinted.containsKey(filename))
                    unvisited.add(filename);
            if (unvisited != null)            
                output += printDependencies(theTable, unvisited, alreadyPrinted);               
        }
    }

    return output;
}

private static void printDependencies(ConcurrentHashMap<String, LinkedList<String>> theTable, ConcurrentLinkedQueue<String> toProcess) {
    String output = ""; 

    for (String current : toProcess) {
        ConcurrentHashMap<String, Boolean> alreadyPrinted = new ConcurrentHashMap<String, Boolean>(); // Keeps track of dependencies already printed
        output += current + ":" + printDependencies(theTable, theTable.get(current), alreadyPrinted) + "\n";
    }

    System.out.println(output);     
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM