【问题标题】:Why isn't my remove node function working?为什么我的删除节点功能不起作用?
【发布时间】:2013-05-24 07:28:51
【问题描述】:

我已经检查了董事会,但找不到任何帮助。我发现在给定基本情况和一般情况的情况下实现递归函数很容易,但这不像我那样工作。我应该迭代一个列表,直到我到达一个链表的尾部。如果下一个节点为 NULL,那么我必须将值存储在最后一个节点,删除该节点,然后返回该值。所以它类似于出队方法,除了它是递归执行的。我究竟做错了什么?

int LinkedList::removeTailRec(Node *n)
{
    // check for the base case(s)
    if(n->next == NULL)
    {
        Node *tmp = new Node();
        tmp = n;
        int val = n->value;
        tmp = NULL;
        return val;
    }
    else
        return removeTailRec(n->next);

    // else call the recursive method
}

【问题讨论】:

  • 我不认为你在做你认为你在用*temp做的事情。
  • new 但没有delete?你是在自找麻烦;)
  • 如果下一个节点为null,则在内存中分配一个新节点,然后通过重新分配其指针指向传入的节点来丢失指向它的指针,然后将指针分配给null,然后从传入的节点返回值,并泄漏已分配节点的内存,由于指针丢失,您无法删除。
  • 您创建一个新节点并使用变量 tmp 获取指向它的 ptr。然后下一行将 tmp 设置为 n,失去对刚刚创建的节点的句柄。你确定这是你想要做的吗?

标签: c++ recursion linked-list


【解决方案1】:

首先,我建议您使用nullptr 而不是NULL。

然后,进入您的代码。您实际上并没有从列表中删除任何内容。

if(n->next == NULL)
{
    Node *tmp = new Node();
                ^^^^^^^^^^
    //Useless, and dangerous. This memory is never free'd

    tmp = n;
    int val = n->value;
    tmp = NULL;
    ^^^^^^^^^^
    //You just set a local variable to NULL, you're not deleting anything

    return val;
}

如果要删除节点,则必须保留对前一个节点的引用(例如,具有双向链表,即具有指向下一个元素的指针指向每个节点中前一个元素的指针,或者直接在前一个节点上工作)。

将前一个节点的next设置为nullptr,存储该节点的值,然后删除Node指针。

一种方法是使用指向下一个节点的指针:

int LinkedList::removeTailRec(Node *n)
{
    //EDIT: Adding a check for n validity
    if(!n){
        //Here, you should have a way of detecting 
        //a call to your method with a null pointer
        return 0;
    }

    Node* nextNode = n->next;
    // check for the base case(s)
    if(nextNode->next == nullptr)
    {
        //Get the next node value
        int val = nextNode->value;

        //Set the current node next member to nullptr
        n->next = nullptr;

        //Free the last node
        delete nextNode;

        return val;
    }
    else{
        return removeTailRec(n->next);
    }

    // else call the recursive method
}

【讨论】:

    【解决方案2】:

    您正在存储结果,但没有将其从链表中删除。您可以在另一个变量中返回结果(指针:结果)。

    Node* getTail(Node *n,int *result){
        //u can even free the memory
        if(!n->next)
        {
           result=n->value;
           return NULL;
        }
        n->next=getTail(n->next,result);
    }
    

    或者你可以用其他方式来做

    int getTail(Node *n)
    {
        if(!n) return 0;
        if(n->next)
        {
            if(!n->next->next)
            {
                Node *frnode=n->next;
                int result=n->next->value;
                n->next=NULL;
                delete frnode;
                return result;
            }
         getTail(n->next);
    }
    

    【讨论】:

    • err 你这里有一些问题......你不应该做 n->next->next :^) 你在递归中
    • @JBL 如果列表只有 1 个元素,您的代码不会导致错误吗? n->next 为 NULL; nextnode->next == NULL 它的错误对吗?
    【解决方案3】:

    您没有删除代码中的最后一个节点,而是在此处泄漏了另一个(临时)节点。 要删除最后一个节点,您必须将前一个节点中的链接归零。 你的代码应该是这样的

    ...
    if (n == NULL || n->next == NULL)
        throw std::out_of_range("node");
    if(n->next->next == NULL)
    {
        int val = n->next->value;
        delete n->next;
        n->next = NULL;
        return val;
    }
    else ...
    

    请注意,c++ 不是一种函数式语言,并且没有对尾递归进行优化,因此在实际应用程序中,当您的列表变得足够大时,您最终会因堆栈溢出而失败 =) 为此使用 Haskell 或 Erlang编程风格,在 c++ 中使用 forwhile

    【讨论】:

      【解决方案4】:

      当n为尾节点时,应将节点n的前一个节点的下一个字段设置为NULL。

      【讨论】:

        猜你喜欢
        • 2019-04-03
        • 2018-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-29
        • 1970-01-01
        • 2020-05-23
        • 1970-01-01
        相关资源
        最近更新 更多