2017-08-19 67 views
0

我正在處理後綴樹。據我所知,我已經正確運行了Ukkonen的算法,可以從任意數量的字符串中構建通用後綴樹。我現在試圖實現一個find_longest_common_substring()方法來做到這一點。爲了這個工作,我知道我需要在樹中的所有字符串之間找到最深的共享邊(字符深度而不是邊),並且我一直在掙扎幾天來獲得遍歷權。通用後綴樹遍歷查找最長公共子串

現在我在C++中有以下內容。我會盡量提供所有代碼,但對於上下文,我將每個節點的邊緣保留在一個名爲outgoing_edges的unordered_map中,並且每個邊都有一個包含識別添加的字符串的整數的整數的向量recorded_strings。邊緣的child字段是它要去的節點,並且lr分別標識其左邊和右邊的索引。最後,current_string_number是樹中當前的字符串數量。

SuffixTree::Edge * SuffixTree::find_deepest_shared_edge(SuffixTree::Node * start, int current_length, int &longest) { 
    Edge * deepest_shared_edge = new Edge; 
    auto it = start->outgoing_edges.begin(); 
    while (it != start->outgoing_edges.end()) { 
     if (it->second->recorded_strings.size() == current_string_number + 1) { 
      int edge_length = it->second->r - it->second->l + 1; 
      int path_length = current_length + edge_length; 
      find_deepest_shared_edge(it->second->child, path_length, longest); 
      if (path_length > longest) { 
       longest = path_length; 
       deepest_shared_edge = it->second; 
      } 
     } 
     it++; 
    } 
    return deepest_shared_edge; 
} 

當試圖調試,盡我所知道的,遍歷運行大部分的罰款,並正確地記錄路徑長度,並設置最長。然而,由於我不太明白的原因,在最有條件的情況下,deepest_shared_edge有時似乎更新到錯誤的邊緣。我懷疑我可能不太瞭解it->second在整個遞歸中如何更新。但我不太清楚如何去解決這個問題。

我知道this類似的問題,但方法似乎有足夠的差異,我不太確定它是如何適用於此。

我主要是爲了好玩和學習,所以我不一定需要工作代碼來替換上面的僞代碼,或者只是對我困惑的地方的任何解釋都一樣。

回答

1

您對deepest_shared_edge的處理是錯誤的。首先,你在函數啓動時做的分配是內存泄漏,因爲你永遠不會釋放內存。其次,遞歸調用的結果將被忽略,因此找到的最深邊緣會丟失(儘管您更新了深度,但不會跟蹤最深的邊緣)。

爲了解決這個問題,您應該通過deepest_shared_edge作爲基準參數(像你這樣做longest),或者你可以把它初始化爲nullptr,然後檢查您的遞歸調用爲nullptr回報並適當地更新。