删除二叉搜索树的根节点

时间:2014-07-01 08:25:44

标签: c++ nodes binary-search-tree treenode

我有这个函数用于删除二进制搜索树中的节点,在我要求它删除根节点的情况下,该节点似乎工作在EXCEPT之外。它应该在左边取最右边的值并用它替换节点;但是,一旦发生这种情况,新的根节点的子指针似乎并不指向原始根节点的子节点。代码如下:

bool delete_node(Node*& root, TYPE data) {
Node* toDelete;
Node* parent;

// This function is defined appropriately elsewhere, and finds the target to be deleted
toDelete = find(data, root);

if (!toDelete) {
    return false;
}

// This function is defined appropriately elsewhere, and finds the parent of the node to be deleted
parent = find_parent(root, toDelete);

// Other cases left out because they work
// If the target node has two children:
if (toDelete->left && toDelete->right) 
{

    // find rightmost child on left that is a leaf
    Node *replacement = toDelete->left;
    while (replacement->right) 
    {
        replacement = replacement->right;
    }

    // set the target node's data
    toDelete->data = replacement->data;
    if (parent) 
    {
        if ( parent->data < toDelete->data ) 
        {
            parent->right = replacement;
        } else
        {
            parent->left = replacement;
        }
    } else 
    {
        // if node has no parents, then it is the root and should be replaced with replacement
        // This line here is what seems to be causing my trouble...I think
        root = replacement;
    }
    parent = find_parent(toDelete, replacement);
    if (parent) 
    {
        if (parent->left == replacement)
            parent->left = NULL;
        else
            parent->right = NULL;
    }
    delete toDelete;
    return true; 
}
}

提前致谢!

2 个答案:

答案 0 :(得分:1)

我最终想到的是:跟踪在替换要删除的节点的节点上方的父节点。然后将有两种情况需要考虑:父节点是要删除的节点,父节点不是要删除的节点。通过在正确的情况下替换树的适当部分,树的结构和不变量保持正常,并且成功删除要删除的节点。从技术上讲,它将是要删除的节点上的数据。

else if (toDelete->left != NULL && toDelete->right != NULL) {

    // find rightmost child on left that is a leaf
    Node* replacement = toDelete->left;
    parent = toDelete;
    // parent is now the parent of the replacement
    while ( replacement->right ) {
        parent = replacement;
        replacement = replacement->right;
    } // By the end, parent will be the node one above replacement

    toDelete->key = replacement->key;

    if (parent == target) 
        parent->left = replacement->left;
    else 
        parent->right = replacement->left;

    delete replacement;
    return true;
}

答案 1 :(得分:0)

这就是我做的工作。只需检查节点是否为根节点,如果是,则设置新根节点。以下是我的工作代码。标有星号的三个地方是我加入它以使它起作用的地方。所有其他代码行都只是标准的教科书理论。

inline NamesBinaryTree::Node* NamesBinaryTree::Node::removeNode (Node*& node, const Female* female, stringComparisonFunction s) {  // Taken from p.253 of Alex Allain's "Jumping Into C++".
    if (!node)
        return nullptr;
    if (node->femaleInfo.first == female->getName()) {
        if (!node->left) {  // i.e. node has either one child or zero children.
            Node* rightNode = node->right;
            if (node->isRoot())  // ***
                namesBinaryTree.setRoot(rightNode);  // Tested to work correctly.  Note that we cannot call 'delete node;', since that will delete the very root that we are setting!
            else
                delete node;        
            return rightNode;  // This will return nullptr if node->right is also nullptr, which is what we would want to do anyway since that would mean that node has zero children.
        }
        if (!node->right) {  // i.e. node has exactly one child, namely its left child, in which case return that left child.
            Node* leftNode = node->left;
            if (node->isRoot())  // ***
                namesBinaryTree.setRoot(leftNode);
            else
                delete node;
            return leftNode;  // This will never be nullptr, else the previous if condition would have been met instead.
        }
        Node* maxNode = findMaxNode(node->left);  // node has two children, so it shall be replaced by the largest valued node in its left subtree.
        maxNode->left = removeMaxNode(node->left, maxNode);  // Note that maxNode->left = node->left is not enough because without actually removing maxNode, the node that was pointing to maxNode will now be pointing to maxNode in its new position (and the subtree under it), and the subtree that was under maxNode will now be gone.
        maxNode->right = node->right;
        if (node->isRoot())  // ***
            namesBinaryTree.setRoot(maxNode);  // Tested to work correctly.
        else
            delete node;
        return maxNode;
    }
    else {
        const int result = (*s)(female->getName(), node->femaleInfo.first); 
        if (result < 0) 
            node->left = removeNode(node->left, female, s);  // This assignment can only work if node is passed by reference (hence the parameter Node*& node), at least this is what "C++ Essentials" did in their solution, p.247.
        else  // Don't use 'else if (result > 0)'.  Let the equality case be covered here too (just as in NamesBinaryTree::Node::insertNode).
            node->right = removeNode(node->right, female, s);  // Again, this assignment can only work if node is passed by reference (hence the parameter Node*& node).
    }
    return node;  // So if node->femaleInfo.first != female->getName(), then the same node is returned, which means that the two assignment lines above don't change any values.
}