【问题标题】:Trouble Modifying Calling Pointer in Recursion在递归中修改调用指针时遇到问题
【发布时间】:2011-12-23 07:42:39
【问题描述】:

所以我正在开发 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--;
    }
}

【问题讨论】:

  • 您有实际问题吗?
  • @KerrekSB 抱歉,我一定是跑题了。感谢您指出。

标签: c++ pointers data-structures recursion


【解决方案1】:

我想我看到了。当您从Erase() 调用RemoveNode() 时,您将值&amp;node 传递给它。改为传入N

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

所以,既然你将&amp;node 传递给RemoveNode()node 就会发生变化。不是*N - 它在其他地方。但如果你通过了,你就改变了你想要的。

希望有帮助!

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

【讨论】:

  • 很好地抓住了本地范围,在几个地方犯了这个错误(我猜没有考虑过)。谢谢!
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多