使用指向指针

时间:2015-10-27 16:37:25

标签: c++ pointers binary-search-tree

我有一个BinarySearchTree结构:

struct BSTNode {
    int value;
    BSTNode *left = nullptr;
    BSTNode *right = nullptr;
};
struct BST {
    BSTNode *root = nullptr;
};

使用这个树的一些函数:

BSTNode **findPosition(BSTNode *node, int value) {
    if (value < node->value) {
        if (node->left) {
            return findPosition(node->left, value);
        } else {
            return &node->left;
        }
    }
    if (value > node->value) {
        if (node->right) {
            return findPosition(node->right, value);
        } else {
            return &node->right;
        }
    }
    return &node;
}
void remove(BSTNode** position, int value) {
    if ((*position)->left == nullptr && (*position)->right == nullptr) {
        delete (*position);
        *position= nullptr;
    }
}
void remove(BST &bst, int value) {
    BSTNode **position = findPosition(bst.root, value);
    if (*position != nullptr) {
        remove(position,value);
    }
}

void add(BSTNode *node, int value) {
    BSTNode **position = findPosition(node, value);

    BSTNode *newNode = new BSTNode;
    newNode->value = value;

    *position = newNode;
}

void add(BST &bst, int value) {
    if (!bst.root) {
        BSTNode *root = new BSTNode;
        root->value = value;
        bst.root = root;
    } else {
        add(bst.root, value);
    }
}

添加工作正常,但删除元素工作奇怪(现在它应该只适用于叶节点)。它只是将节点的值设置为零。我认为问题在于我使用指针。

我做错了什么?

3 个答案:

答案 0 :(得分:1)

return &node;中的最终案例FindPosition是错误的。它返回垃圾。

如果您将签名更改为 BSTNode **findPosition(BSTNode *&node, int value)

然后在许多用途中将修复最终的回报。我没有(或取决于你有什么与你发布的内容不能)检查所有用途,看看是否涵盖了你使用findPosition的各种方式。

在不更改签名的情况下,您将返回调用参数的地址,该地址在返回值可以使用时无效。通过该签名更改,相同的返回指令将返回正确的地址。 签名更改表示对findPosition与其调用方之间的合同进行了重大更改,因此仅当所有调用方的更改都正常时,它才有效。否则,你需要做出更大的改变。没有改变只是findPosition可以工作而不改变与其调用者的合同。

编辑(因为你的评论)。在最终返回指令中,您需要返回该指针的原始地址。如果没有签名更改,则返回指针副本的地址。通过签名更改,函数的语法仍然将node视为指针,但在其语义中隐藏了额外的间接级别。使用额外的间接级别,该指针的原始地址可用(并由&node计算)而不是副本的地址。

另外(基于dasblinkenlight的答案)在你的版本的许多地方都需要测试NULL指针,这很容易出错。如果您将该测试推送到findPosition的顶部,则需要更少的位置且更强大:

BSTNode **findPosition(BSTNode *&node, int value) {
    if ( node )
    {    
        if (value < node->value) {
            return findPosition(node->left, value);
        } 
        if (value > node->value) {
            return findPosition(node->right, value);
        }
    }
    return &node;
}

答案 1 :(得分:1)

/usr/local/include/boost/serialization/access.hpp:118:9: error: 'class boost::tuples::tuple<int, int, int, int, int>' has no member named 'serialize' t.serialize(ar, file_version);

findPosition

返回参数的地址 在函数之外取消引用它是未定义的。

目前还不清楚为什么函数会返回一个指针的地址。

您需要重新考虑删除策略;为了删除节点,您需要修改其父节点的子指针。

答案 2 :(得分:1)

您的代码有未定义的行为:

return &node;

返回函数参数的地址,这意味着任何取消引用findPosition的返回值都会导致未定义的行为。

您可以通过确保findPosition引用指针而不是指针来避免此问题:

BSTNode **findPosition(BSTNode*& node, int value) {
    if (node == nullptr) {
        return &node;
    }
    ... // The rest of the code remains the same
}

请注意,虽然return &node的语法保持完全相同,但行为却不同,因为在函数退出后,引用指针的地址仍然有效。

注意:除非这是使用C ++语法编写C代码的学习练习,否则请考虑重构代码以在BSTNode内封装BST,并将树功能公开为成员功能