正确退出递归?

时间:2016-12-28 21:25:58

标签: c++ recursion trie

TrieNode和Trie对象:

struct TrieNode {

    char nodeChar = NULL;
    map<char, TrieNode> children;

    TrieNode() {}
    TrieNode(char c) { nodeChar = c; }
};


struct Trie {
    TrieNode *root = new TrieNode();
    typedef pair<char, TrieNode> letter;
    typedef map<char, TrieNode>::iterator it;

    Trie(vector<string> dictionary) {
        for (int i = 0; i < dictionary.size(); i++) {
            insert(dictionary[i]);
        }
    }

    void insert(string toInsert) {
        TrieNode * curr = root;
        int increment = 0;
        // while letters still exist within the trie traverse through the trie
        while (curr->children.find(toInsert[increment]) != curr->children.end()) { //letter found
            curr = &(curr->children.find(toInsert[increment])->second);
            increment++;
        }
        //when it doesn't exist we know that this will be a new branch 
        for (int i = increment; i < toInsert.length(); i++) {
            TrieNode temp(toInsert[i]);
            curr->children.insert(letter(toInsert[i], temp));
            curr = &(curr->children.find(toInsert[i])->second);
            if (i == toInsert.length() - 1) {
                temp.nodeChar = NULL;
                curr->children.insert(letter(NULL, temp));
            }

        }
    }


    vector<string> findPre(string pre) {
        vector<string> list;
        TrieNode * curr = root;
        /*First find if the pre actually exist*/
        for (int i = 0; i < pre.length(); i++) {
            if (curr->children.find(pre[i]) == curr->children.end()) { //DNE
                return list;
            }
            else {
                curr = &(curr->children.find(pre[i])->second);
            }
        }
        /*Now curr is at the end of the prefix, now we will perform a DFS*/

        pre = pre.substr(0, pre.length() - 1);
        findPre(list, curr, pre);

    }

    void findPre(vector<string> &list, TrieNode *curr, string prefix) {
        if (curr->nodeChar == NULL) {
            list.push_back(prefix);
            return;
        }
        else {
            prefix += curr->nodeChar;
            for (it i = curr->children.begin(); i != curr->children.end(); i++) {
                findPre(list, &i->second, prefix);
            }

        }
    }



};

问题在于这个功能:

void findPre(vector<string> &list, TrieNode *curr, string prefix) {

/*if children of TrieNode contains NULL char, it means this branch up to this point is a complete word*/
    if (curr->nodeChar == NULL) { 
        list.push_back(prefix);
    }
    else {
        prefix += curr->nodeChar;
        for (it i = curr->children.begin(); i != curr->children.end(); i++) {
            findPre(list, &i->second, prefix);
        }

    }
}

目的是使用DFS从trie返回所有具有相同前缀的单词。我设法检索所有必要的字符串,但我不能退出递归。

代码完成if语句的最后一次迭代并中断。 Visual Studio不会返回任何错误代码。

3 个答案:

答案 0 :(得分:2)

递归的典型结束就像你说的那样 - return所有单词。标准递归看起来像这样:

returnType function(params...){
    //Do stuff
    if(need to recurse){
        return function(next params...);
    }else{ //This should be your defined base-case
        return base-case;
}

问题在于你的递归函数永远不会返回 - 它既可以执行push_back,也可以再次调用自身。这些似乎都没有正确退出,所以它要么安静地结束(推断没有返回),要么它会继续递归。

在您的情况下,您可能需要将递归结果存储在类似列表等的中间结构中,然后在迭代后返回该列表(因为它是树搜索并且应该检查所有子项,而不是返回只有第一个)

就这一点而言,你似乎错过了递归点的一部分 - 它们的存在是为了填补一个目的:将问题分解成碎片,直到这些碎片无法解决。然后返回该案例并构建回完整的解决方案。任何树木搜索都必须来自这个基础结构,否则您可能会遗漏某些内容,例如忘记return您的结果。

答案 1 :(得分:1)

检查Trie结构的完整性。该功能似乎是正确的。它不会终止的原因是你的一个或多个叶子节点没有curr-> nodeChar == NULL。

另一种情况是任何节点(叶子或非叶子)都有一个垃圾子节点。这将导致递归破坏读取垃圾值而没有理由停止。在调试模式下运行应该会因分段错误而中断执行。

编写另一个函数来测试所有叶节点是否都有NULL终止。

编辑:

发布代码后,原始海报已经指出问题在于他/她没有返回字符串列表。

除此之外,我还想根据代码提供更多建议:

如果toInsert字符串已经在Trie中,这个while循环如何终止。 您将超出toInsert字符串并读取垃圾字符。 它会在此之后退出,但超出字符串读取是一种糟糕的编程方式。

// while letters still exist within the trie traverse through the trie
while (curr->children.find(toInsert[increment]) != curr->children.end()) 
{ //letter found
    curr = &(curr->children.find(toInsert[increment])->second);
    increment++;
}

这可以写成如下:

while (increment < toInsert.length() && 
curr->children.find(toInsert[increment]) != curr->children.end())

此外,

Trie( vector<string> dictionary)

应该是

Trie( const vector<string>& dictionary )

因为字典可以是一个大对象。如果您没有通过引用传递,它将创建第二个副本。这效率不高。

答案 2 :(得分:0)

我是个白痴。我忘了在第一个findPre()函数上返回列表。

> dput(gdd10csum)
structure(list(Date = structure(c(16941, 16941, 16941, 16941, 
16941, 16941, 16941, 16941, 16941, 16941, 16941, 16942, 16941, 
16941, 16941, 16941, 16942, 16942, 16941, 16942, 16942, 16942, 
16942, 16941, 16941, 16942, 16942, 16941, 16942, 16941, 16941, 
16941, 16941, 16942, 16941, 16942, 16942, 16942, 16941, 16941, 
16941, 16942, 16941, 16941, 16941, 16941, 16941, 16942, 16942, 
16942, 16942, 16942, 16942, 16942, 16942, 16942, 16942, 16942, 
16942, 16942, 16942, 16942, 16942, 16942), class = "Date"), Treatment = structure(c(2L, 
1L, 5L, 3L, 1L, 5L, 2L, 3L, 5L, 5L, 4L, 2L, 4L, 3L, 4L, 4L, 1L, 
5L, 2L, 5L, 3L, 1L, 2L, 2L, 2L, 5L, 3L, 1L, 5L, 5L, 1L, 5L, 1L, 
4L, 3L, 4L, 3L, 4L, 3L, 1L, 4L, 4L, 5L, 3L, 3L, 4L, 4L, 2L, 2L, 
2L, 1L, 5L, 1L, 5L, 1L, 3L, 3L, 4L, 1L, 5L, 3L, 3L, 4L, 4L), .Label = c("Disc", 
"Strip_NT", "Strip_ST", "Vt_high", "Vt_low"), class = "factor"), 
    Rep = structure(c(2L, 1L, 1L, 2L, 2L, 4L, 1L, 3L, 2L, 3L, 
    4L, 2L, 1L, 1L, 2L, 3L, 1L, 1L, 2L, 4L, 2L, 2L, 1L, 1L, 3L, 
    2L, 3L, 1L, 3L, 1L, 4L, 4L, 3L, 4L, 2L, 1L, 1L, 2L, 4L, 2L, 
    1L, 3L, 2L, 3L, 1L, 3L, 2L, 2L, 3L, 1L, 1L, 1L, 4L, 4L, 3L, 
    2L, 4L, 1L, 2L, 2L, 3L, 1L, 3L, 2L), .Label = c("1", "2", 
    "3", "4"), class = "factor"), Depth = structure(c(2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 1L, 2L, 2L, 2L, 2L, 1L, 1L, 2L, 2L, 1L, 2L, 1L, 1L, 1L, 
    1L, 2L, 1L, 2L, 2L, 2L, 1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L), .Label = c("5", "30"), class = "factor"), sum = c(19.264, 
    27.405, 37.078, 40.186, 40.838, 42.793, 44.761, 47.656, 47.842, 
    53.317, 59.739, 40.824, 60.351, 61.321, 62.353, 64.521, 47.445, 
    55.643, 94.985, 59.336, 62.25, 63.425, 64.323, 110.563, 110.912, 
    68.41, 68.735, 116.45, 73.875, 127.29, 129.475, 130.305, 
    133.851, 78.288, 139.362, 79.38, 80.889, 83.889, 147.819, 
    150.538, 150.655, 89.098, 156.007, 159.148, 168.585, 173.395, 
    175.571, 116.011, 128.453, 129.605, 133.488, 140.31, 139.496, 
    143.325, 150.379, 153.905, 157.835, 163.186, 166.053, 174.543, 
    175.186, 176.603, 190.917, 192.106), cumsum = c(19.264, 27.405, 
    37.078, 40.186, 40.838, 42.793, 44.761, 47.656, 47.842, 53.317, 
    59.739, 60.088, 60.351, 61.321, 62.353, 64.521, 74.85, 92.721, 
    94.985, 102.129, 102.436, 104.263, 109.084, 110.563, 110.912, 
    116.252, 116.391, 116.45, 127.192, 127.29, 129.475, 130.305, 
    133.851, 138.027, 139.362, 139.731, 142.21, 146.242, 147.819, 
    150.538, 150.655, 153.619, 156.007, 159.148, 168.585, 173.395, 
    175.571, 210.996, 239.365, 240.168, 249.938, 267.6, 268.971, 
    273.63, 284.23, 293.267, 305.654, 313.841, 316.591, 330.55, 
    334.334, 345.188, 364.312, 367.677)), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -64L), vars = list(
    Treatment, Rep, Depth), indices = list(c(27L, 50L), c(1L, 
16L), c(39L, 58L), c(4L, 21L), c(32L, 54L), c(30L, 52L), c(23L, 
49L), c(6L, 22L), c(18L, 47L), c(0L, 11L), c(24L, 48L), c(44L, 
61L), c(13L, 36L), c(34L, 55L), c(3L, 20L), c(43L, 60L), c(7L, 
26L), c(38L, 56L), c(40L, 57L), c(12L, 35L), c(46L, 63L), c(14L, 
37L), c(45L, 62L), c(15L, 41L), c(10L, 33L), c(29L, 51L), c(2L, 
17L), c(42L, 59L), c(8L, 25L), c(9L, 28L), c(31L, 53L), c(5L, 
19L)), drop = TRUE, group_sizes = c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), biggest_group_size = 2L, .Names = c("Date", 
"Treatment", "Rep", "Depth", "sum", "cumsum"), labels = structure(list(
    Treatment = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 
    2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 
    4L, 5L, 5L, 5L, 5L, 5L, 5L, 5L), .Label = c("Disc", "Strip_NT", 
    "Strip_ST", "Vt_high", "Vt_low"), class = "factor"), Rep = structure(c(1L, 
    1L, 2L, 2L, 3L, 4L, 1L, 1L, 2L, 2L, 3L, 1L, 1L, 2L, 2L, 3L, 
    3L, 4L, 1L, 1L, 2L, 2L, 3L, 3L, 4L, 1L, 1L, 2L, 2L, 3L, 4L, 
    4L), .Label = c("1", "2", "3", "4"), class = "factor"), Depth = structure(c(1L, 
    2L, 1L, 2L, 1L, 1L, 1L, 2L, 1L, 2L, 1L, 1L, 2L, 1L, 2L, 1L, 
    2L, 1L, 1L, 2L, 1L, 2L, 1L, 2L, 2L, 1L, 2L, 1L, 2L, 2L, 1L, 
    2L), .Label = c("5", "30"), class = "factor")), class = "data.frame", row.names = c(NA, 
-32L), vars = list(Treatment, Rep, Depth), indices = list(c(34L, 
40L), c(1L, 8L), c(48L, 55L), c(5L, 19L), c(41L, 47L), c(37L, 
43L), c(31L, 38L), c(7L, 20L), c(30L, 33L), c(0L, 4L), c(32L, 
36L), c(56L, 61L), c(16L, 27L), c(42L, 50L), c(3L, 17L), c(53L, 
59L), c(9L, 23L), c(46L, 52L), c(49L, 54L), c(15L, 26L), c(60L, 
63L), c(18L, 28L), c(57L, 62L), c(21L, 29L), c(14L, 25L), c(35L, 
44L), c(2L, 12L), c(51L, 58L), c(10L, 22L), c(11L, 24L), c(39L, 
45L), c(6L, 13L)), drop = TRUE, group_sizes = c(2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), biggest_group_size = 2L, .Names = c("Treatment", 
"Rep", "Depth")))