无法在递归中修改调用指针

时间:2011-11-07 01:00:14

标签: c++ pointers data-structures recursion

所以我正在开发BST,构建删除工具。

我的代码序列似乎工作正常 - 保存不更新父或根,并将发送它的指针设置为已删除的节点的地址为NULL。

我正在向Erase和RemoveNode函数中的指针传递指针,以便直接影响实际导致递归调用的左,右或根数据成员。在遍历代码时,它在remove函数中将* N设置为NULL,但这不会反映在调用对象的数据中。我使用指针指针方法不正确吗?如果是这样,有没有办法可以递归删除,并且如果链接被破坏,能够修改先前的节点?

节点结构:

struct tNode
{
    tNode(int n)
    {
        data = n; 
        left = NULL; 
        right = NULL;
    }

    //Works, cleans all linked objects. 
    //Must remember to null links when removing wanted nodes
    ~tNode(void)
    {
        //cout << "Deleting " << data << endl;
        delete left;
        delete right;
    }

    // Data members
    int data;
    tNode* left;
    tNode* right;
};

橡皮擦功能来递归树:

    void BinSearchTree::Erase(int n, tNode** N)
    {
        tNode* node = *N;
        if (root)
        {
            if (node->data > n) // post order, to avoid moving many times over
            {
                if (node->left)
                {
                    Erase(n, &node->left);
                }
            }
            else
            {
                if (node->right)
                {
                    Erase(n, &node->right);
                }
            }

            if (node->data == n)
            {
                RemoveNode(&node);
            }
        }
    }

用于处理实际删除的RemoveNode函数:

void BinSearchTree::RemoveNode(tNode** N)
{
    tNode* node = *N;
    if (!node->left && !node->right) // is leaf
    {
        delete node; // remove node
        size--;
        *N = NULL; // null pointer for above node/structure
    }
    else if (!node->left) // right child
    {
        tNode* temp = node->right; // to strip out copied node when finished
        node->data = node->right->data; // copy right node into current node
        node->right = node->right->right;
        node->left = node->right->left;

        temp->right = NULL; // NULL because node destructor is recursive
        temp->left = NULL; // ^^
        delete temp;
        size--;
    }
    else if (!node->right) // left child
    {
        tNode* temp = node->left; // to strip out copied node when finished
        node->data = node->left->data; // copy left node into current node
        node->right = node->left->right;
        node->left = node->left->left;

        temp->right = NULL; // NULL because node destructor is recursive
        temp->left = NULL; // ^^
        delete temp;
        size--;
    }
    else // 2 children
    {
        tNode* temp = node->right; // find ideal child -> left-most right child
        tNode* parent = NULL; // keep track of owner of ideal child
        while (temp->left)
        {
            parent = temp;
            temp = temp->left;
        }

        node->data = temp->data; // copy ideal child to root
        if (parent)
        {
            parent->left = temp->right; // case that left-most child has right child of it's own
        }
        RemoveNode(&temp);
        size--;
    }
}

2 个答案:

答案 0 :(得分:1)

我想我明白了。当您从RemoveNode()致电Erase()时,您会传递值&node。改为通过N

以下是发生的事情:行tNode* node = *N;在堆栈上创建一个局部变量。 *N副本。虽然该变量与* N(起初)具有相同的值,但它存储在内存中的不同位置:node位于堆栈中,*N位于堆中的某个位置。

因此,自从&node传递给RemoveNode()后,node就会发生变化。不是*N - 它在其他地方。但如果你传入,你就会改变你想要的东西。

希望有所帮助!

PS:如果不清楚,请告诉我!写关于双指针可能比使用它们更难......

答案 1 :(得分:0)

省去使用双指针的麻烦,只需使用对指针的引用。它们具有与普通指针相同的语义,但是分配它们实际上会改变传递的指针。

void BinSearchTree::Erase(int item, tNode*& node);

此外,使用富有表现力的名称并保存循环的单字母变量名称。