【问题标题】:Binary tree traversal causes stack overflow二叉树遍历导致栈溢出
【发布时间】:2015-07-25 03:44:18
【问题描述】:

所以我正在做一个通过数组实现的二叉搜索树(如果父母的索引是i,那么左孩子的索引是(i * 2 + 1),右孩子的索引是(i * 2 + 2)。

每当我尝试(按顺序)遍历树时,我都会在第 3 次预排序函数调用期间遇到堆栈溢出。

这是我的预订功能代码:

void traversePreOrder(Tree tree, int index)
{
    printf("%d\n", index); //debug
    if (tree.data[index].accNumber != 0) //all .accNumber values are initialized as 0
                                   // at the start of the program to mark empty nodes.
    {
        printf("printing: %d\n", index); //debug
        printNode(tree.data[index]);

        if (tree.data[index * 2 + 1].accNumber != 0)
        {
            printf("will print: %d\n", index * 2 + 1); //debug
            traversePreOrder(tree, index * 2 + 1);
        }

        if (tree.data[index * 2 + 2].accNumber != 0)
        {
            printf("will print: %d\n", index * 2 + 2); //debug
            traversePreOrder(tree, index * 2 + 2);
        }
    }
    else
        return;
}

这是前序遍历的输出:

0
printing: 0
User: Dumbledore
Account number: 53167
Account type: public
Account balance: 4597.54
Is account in debt? Yes

will print: 1
1
printing: 1
User: Stark
Account number: 13497
Account type: private
Account balance: 1549.50
Is account in debt? No

will print: 3

Process returned  255 (0xFF)   execution time : 5.856 s
Press any key to continue.

这棵树应该是这样的:

(only accNumber values)
                    53167
                  /       \
              13457      74310
                 \       /   \
               43158  71401  79473
                /      /       \
             14741   69690    99751

感谢您的帮助。


更新

将最大树容量从 1000 更改为 50 以某种方式解决了这个问题。如果有人能解释原因,那就太好了。

【问题讨论】:

  • 我强烈怀疑您正在读取超出数组中初始化数据的内容,因此会永远递归。作为一个快速测试,您能否确保将整个 tree.data[] 结构清除为 0(以便读取尚未写入的数据返回 0 并正常失败)以便排除这种情况?
  • 在我创建树之后我使用这个函数: void initializeTree(Tree * tree) { if (tree == NULL) return; for (int i = 0; i data[i].accNumber = 0; } }
  • 您无法探测data,除非使用的索引已知data的数量级范围内。仅仅因为您的阵列中有一个节点并不意味着它的两个孩子也都在那里。例如:您发布的树可存储在 16 个节点的数组中,当您递归检查索引 15 的 children 时,问问自己代码做了什么。检查 tree.data[index * 2 + 1].accNumber != 0 是不够的。在此之前,您需要知道index * 2 + 10..(n-1) 之内,其中n 首先是data 的大小。
  • @WhozCraig 树的最大容量是 1000 个节点,所以在这种情况下它应该不是问题(或者我没有解释你的评论吗?)。不过感谢您的提示,我会将其添加到代码中。
  • 您的问题中绝对没有关于绝对树容量的信息。你希望别人怎么解释?

标签: c recursion tree stack-overflow traversal


【解决方案1】:

您声明:

所有 .accNumber 值在程序开始时初始化为 0 标记空节点。

这不是递归停止的足够强的标准。

如果你想明确,你应该为索引设置一个上限,并确保你不超过它。例如:如果tree.size iz 是树中的节点数,你还应该在递归的每一步之前进行检查,如下所示:

    int left_child_idx = index * 2 + 1;
    if (tree.data[left_child_idx].accNumber != 0 && left_child_idx < tree.size)
    {
        printf("will print: %d\n", index * 2 + 1); //debug
        traversePreOrder(tree, index * 2 + 1);
    }

或者,如果您不想这样做,您应该确保有两个终止叶,其中 所有 的最后一个节点为 0 accNumber

在这个数据结构中,这实际上意味着您的 data 数组的后半部分应仅由此类终止叶子组成。

看起来很丑,但我希望你能看到:

                      53167
                  /           \
              13457             74310
             /   \            /       \
            0      43158     71401     79473
          /  \     /   \     /    \      /  \
         0    0   14741  0  69690  0    0   99751
        /\    /\   /\    /\   /\   /\   /\   /\
       0  0  0  0 0  0  0  0 0  0 0  0 0  0 0  0    

作为一个数组:

[53167, 13457, 74310, 0, 43158, 71401, 79473, 0, 0, 14741, 0, 69690, 0, 0, 99751,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 

有 31 个元素,99751 是第 15 个。后半部分中的任何一个是否非零,都会溢出。

【讨论】:

    猜你喜欢
    • 2012-05-10
    • 2012-11-09
    • 1970-01-01
    • 1970-01-01
    • 2014-12-07
    • 2014-05-08
    • 2012-01-01
    • 2022-11-11
    相关资源
    最近更新 更多