递归树遍历/分支删除的段错误

时间:2018-06-28 11:13:30

标签: c++ recursion tree segmentation-fault delete-operator

我正在尝试清理的分支,每个节点都存储一个occurrence  每次在构造期间访问该节点的值,在这种意义上,“清理”是指在两个后续节点都只有一个occurrence的点之后删除分支:

因此,5->1->1->1的分支将简单地变成5->1。我使用的是递归树遍历(在打印所有路径时有效),然后是递归删除(在销毁对象时有效):

void tree::cleanBranch(Node *node)
{
    if(!node)
        return;

    int cnt = 0;
    int ind = 0;
    // 4 possible subnodes
    for(int i = 0; i < 4; i++) {
        if(node->subnodes[i]) {
            cnt++;
            ind = i;
        }
        if(cnt > 1)
            break;
    }

    // Only 1 subnode and both current and subnode have occurrence of 1
    if(cnt == 1 && node->occurrences == 1 && 
            node->subnodes[ind]->occurrences == 1) {
        delTree(node->subnodes[ind]);
        return;
    } 

    for(int i = 0; i < 4; i++)
        cleanBranch(node->subnodes[i]);
}

删除功能:

void tree::delTree(Node* node)
{
    if(node) {
        for(int i = 0; i < 4; i++)
            delTree(node->subnodes[i]);
        delete node;
    }
}

但是,它立即出现段错误。然后,我创建了一个简单的树5->1->1,它在第一个节点delete上分段,第三个节点被调用,但是cleanBranch()delTree()都检查它是否不为空删除之前。

我觉得我缺少明显的东西,任何帮助将不胜感激。

编辑

响应 Qubit

说实话,它们真的很简单,tree是:

tree() { root = new Node; }

引用成员Node *root

Node本身具有:

Node(): occurrences(0), subnodes(4)
{
    for(int i = 0; i < 4; i++)
        subnodes[i] = NULL;
}

occurrencesulong的{​​{1}},而subnodesvector的{​​{1}}。

响应 ErikAlapää

我目前不是,但我将其移开并加以破解。

1 个答案:

答案 0 :(得分:0)

提供的代码似乎正确。创建树的方式可能有问题吗?

假设Node就是这样

struct Node
{
    unsigned long occurrences = 0;
    vector<Node*> subnodes;

    Node(): occurrences(0), subnodes(4)
    {
        for(int i = 0; i < 4; i++)
            subnodes[i] = NULL;
    }
};

和类似这样的树创建

// 5->1->1->1
Node* createTree()
{
    Node* root = new Node;
    root->occurrences = 5;

    Node* cur = root;
    for (int i = 0; i < 3; ++i)
    {
        cur->subnodes[0] = new Node;
        cur->subnodes[0]->occurrences = 1;
        cur = cur->subnodes[0];
    }
    return root;
}

(使用您的代码样式) cleanBranch正常。 还添加

node->subnodes[ind] = nullptr;

之后

delTree(node->subnodes[ind]);

否则,如果您不小心在同一棵树上两次调用cleanBranch,则会获得GPF。

顺便说一句,请考虑使用unique_ptr代替Node *。

更新: 节点显然应该有这样的析构函数

~Node()
{
    for (int i = 0; i < subnodes.size(); ++i)
    {
        if (subnodes[i])
        {
            delete subnodes[i];
            subnodes[i] = nullptr; // not nesessary with vector but =)
        }
    }
}

比您没有使用过delTree,只是

delete node->subnodes[ind];
node->subnodes[ind] = nullptr;