2014-12-24 241 views
-2

Qn)只给出一个指向要在单向链表中删除的节点的指针, 如何删除它?删除链接列表

我试图删除最后一个元素,即1但else部分进入一个无限循环 印刷垃圾值。

Original link

int main() 
{ 
    struct Node* head = NULL; 
    push(&head, 1); 
    push(&head, 4); 
    push(&head, 6); 
    push(&head, 8); 
    print(head); 
    del_p(head->next->next->next); 
    cout << endl; 
    print(head); 
    return 0; 
} 

void del_p(struct Node* current) 
{ 
    struct Node* temp; 
    if (current->next != NULL) 
    { 
     temp = current->next; 
     current->data = temp->data; 
     current->next = temp->next; 
     free(temp); 
    } 
    else 
    { 
     free(current); 
     current = NULL; 
    } 
} 
+1

和你在你自己的调试尝试中发现了什么? –

+0

@MartinJames它给出垃圾值,但正如0x499602D2指出的,它现在工作正常 – Rooney10

回答

1

您的功能的else分支尝试重新分配currentNULL。这是有问题的,因为current本地副本传入的指针。也就是说,您不能修改原始指针的值。

这就是您接收垃圾的原因,因为您正在访问内存已被释放的节点。

您也需要一个双指针,或者最好是参考节点:

void del_p(struct Node*& current) 
+0

0x499602D2 void del_p(struct Node * current)对于除结尾之外的所有值都正常工作原因是什么?通过使用参考,我们直接与价值而不是地址一起工作,那么它如何解决这个原始指针问题可以用什么来澄清? U说我访问一个节点的地方已经释放了内存,我在哪里取消了它的分配?请澄清 – Rooney10

+0

@ Rooney10该代码适用于所有值,但最终不使用引用时,因为在'if'分支中您不会修改指针本身而是其成员。 'else'分支做'current = NULL',它改变指针的* copy *。解引用指针(带'*'或' - >')会返回一个引用,但当前不是引用(当然,除非你使用'&)。另外,你用'free()'释放了内存。 – 0x499602D2

0

如果你通过要删除的节点和头节点,然后你可以循环直到找到节点之前的节点被删除。然后您需要将先前节点指向要删除的节点所指向的节点,然后您可以释放要删除的节点。

void delete(struct Node* to_delete, struct Node* head) 
{ 
    // check if node to be deleted is the head 
    if (to_delete == head) 
    { 
     head = to_delete->next; 
     return; 
    } 

    // make a local copy of the head just in case as to not alter it 
    struct Node* tempHead = head; 
    while(tempHead->next != to_delete) 
    { 
     tempHead = tempHead->next; 
    } 
    tempHead->next = to_delete->next; 
    free(to_delete); 
} 

就像一个免责声明我没有测试过这个代码,但从概念上说它应该工作。

+0

如果头节点是要删除的节点,这将不起作用。 – Adam27X

+0

是的。我会编辑。 –

0

删除一个节点的链表将遵循以下步骤的典型算法:

  • 获取一个temp指针在Head开始。
  • 将您的temp移动到您要删除的节点(本例中为最后一个:temp->next == NULL)。
  • 释放内存temp2
  • 将指针temp->next设置为NULL
  • 将指针返回到head

现在,这不是唯一的算法,有很多方法可以实现这一点。下面的代码将是我的解决方案的功能del_p(如果你想删除的最后一个节点):

void del_p(struct Node *head) 
{ 
    if (head != NULL) 
    { 
     struct Node *temp = head; 
     while (temp->next != NULL) temp = temp->next; 
     free(temp); 
    } 
} 

可以使这个代码更一般的,以使其能够删除任何节点,通过传递一个指向该节点(或价值),代码如下所示:

void del_p(struct Node **head, struct Node *delete_node) 
{ 
    if (head != NULL) 
    { 
     struct Node *temp = *head; 
     if (temp == delete_node) 
     { 
      *head = (*head)->next; 
      free(temp); 
     } 
     else 
     { 
      while (temp->next != NULL && temp->next != delete_node) 
       temp = temp->next; 
      if (temp->next != NULL && delete_node != NULL) 
      { 
       temp->next = delete_node->next; 
       free(delete_node); 
      } 
     } 
    } 
} 

希望这对你的作品,这个代码不进行测试,但告诉我,如果你有麻烦!

+0

根据这个问题,我们只能使用当前指针,所以我们不能使用头遍历列表。 – Rooney10

+0

哦,我明白了,解决这个问题的最简单方法是使用带有双指针参数的代码,因为这样可以修改列表中节点的内存,而不是其副本的内容,并将其设置为到'NULL'。 – PatoBeltran

+1

“,因为它现在写入它只会在您将指针交给列表中最后一个节点的指针时才起作用。” - 其实,他的代码适用于每个节点*,但最后一个。事实上,他没有参考指针保持列表中的节点。另外,你显示的第一个例子只删除最后一个节点(不知道这是你的意思),在第二个例子中,head = head-> next不会影响列表中的while和while循环。 'else'分支不能防止'delete_node'不在列表中(因此在这种情况下是无限循环)。 – 0x499602D2