【问题标题】:How do I properly delete nodes of linked list in C++如何在 C++ 中正确删除链表的节点
【发布时间】:2014-04-02 23:53:39
【问题描述】:

我感觉好像我并没有真正删除节点并释放内存。我想我只是在移动指针,所以当我打印链接列表时,列表不会打印我删除的元素。所以我的问题是我实际上是在删除节点还是只是简单地重新排列指针,所以看起来我正在删除节点(基本上只是断开链接但不删除节点)?感谢您的帮助。

void SLL::deleteNode(int target){
Node *current = new Node;
Node *previous = new Node;

for (current = front->next, previous = front; current != NULL; current = current->next, previous=previous->next){
    if (previous->data == target && previous == front){
        front = previous->next;
        delete[] previous;
        return;
    //This if statement deletes the element if its the front
    }

    else {

        if (previous->data == target && previous->next == NULL){
            previous = NULL;
            delete[] current;
            return;
        //This if statement deletes the node if it is the back
        }


        else if (current->data==target)
        {
            previous->next = current->next;
            delete[] current;
            return;
        //This if statement deletes a node if it is in the middle
        }
    }
    }

    delete[] current;
    delete[] previous;
}

【问题讨论】:

  • 当你将currentprevious声明为单个实例时,为什么要使用数组删除(delete [])版本?
  • front->next 开始你的枚举算法是令人担忧的。 告诉我们您没有使用实际上不包含数据的预分配“头”节点。它不是必需的。除非你用new Node[n] 分配你的节点,否则你使用了错误的delete 操作符。
  • 我不知道。我试过这个它有效。请回答问题。
  • 不知道什么?你的前端指针是否是哨兵节点?您的节点是否分配有 vector-new ?你写的代码,对吧?顺便说一句,你在这个函数的头部分配的两个节点会立即被泄露,所以我可以向你保证,无论你是否删除了目标节点,最终回收的内存都是零。
  • delete[] 在你的第二个块中是一个空向量,但我不认为控制可以进入那个块,所以我想它没有实际意义。

标签: c++ linked-list nodes


【解决方案1】:
Node *current  = new Node;
Node *previous = new Node;

此代码会导致内存泄漏 - 您永远不会删除此内存。您可以在不分配内存的情况下声明指针:

Node *current  = nullptr;
Node *previous = nullptr;

delete 将删除指针的内存,因此您实际上将删除节点。 但是将delete[] 用于Node* 不正确,它应该只用于数组——用new[] 分配的内存。使用不当会导致未定义的行为。 因此,要正确删除节点,请使用运算符 delete 删除它们。

使用内存泄漏检测工具了解您的程序是否存在内存泄漏。

删除列表元素的代码:比如说,我们有指向列表头部的 pHead (但如果你自己写这样的东西,它会给你更多):

Node* pCur  = pHead;
Node* pPrev = pCur;

while (pCur && pCur->data != target) {
    pPrev = pCur;
    pCur  = pCur->next;
}

if (pCur==nullptr)  // not found
   return NOT_FOUND;

if (pCur == pHead) {   // first element matches
    pHead = pCur->next;
} else {
    pPrev->next = pCur->next;
}

// pCur now is excluded from the list

delete pCur;     // deallocate its memory

使用指针到指针的替代方法(社区加法)

当您使用列表中的实际指针 来执行枚举时,上述内容可以呈现新的亮点。下面以pp 开始,分配头指针的地址(不是它指向的节点;实际的指针本身)。我们遍历列表,直到pp 保存指向要删除目标的节点的指针的地址(可以是头指针,也可以是某个节点中的next 指针,没有区别)。被寻址的指针被设置为它自己节点的next值,然后目标节点被删除。

这确实应该在调试器中观察以了解它是如何工作的,但是考虑到实际情况,算法非常简单:

Node **pp = &pHead;
while (*pp && (*pp)->data != target)
    pp = &(*pp)->next;

if (*pp)
{
    Node *victim = *pp;
    *pp = victim->next;
    delete victim;
}

全部。而且您可以免费删除头节点,而无需对其进行特殊处理。希望这也有帮助。

【讨论】:

  • 谢谢。从现在开始,我将不再为他们使用 new 。虽然我的问题仍然存在,但如何删除我的目标节点?我知道你谈到了它,但你能不能再解释一下。
  • @user3291106 - 我提供了一个示例代码。但是你自己写会更有用。现在试试双链表,比如从头开始搜索。
  • @Alex 当pHead 指向将被删除的节点时,这将如何完成?跟随:while 循环将被跳过并且什么也不做。 pHead->next 将有效地分配给它自己,因为pPrevpCurpHead 都指向同一个节点。然后头节点将被delete pCur; 销毁,从而使列表的整个其余部分成为孤立的,并使所有三个指针都持有一个无效的、不确定的地址。总之,哎哟
  • @WhozCraig 感谢您的指正!修复。虽然我更希望 user3291106 告诉我 :) 我不需要急于发布代码,同意。
  • @Alex 没问题。看看附录。不确定你是否曾经看过它,但它值得一看。并 +1 坚持答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-02
  • 2016-03-02
相关资源
最近更新 更多