仅指定指向该节点的指针时,从单个链表中删除任何节点

时间:2012-02-20 14:39:35

标签: data-structures linked-list

这是一个在采访中向我提出的问题。

“内存中存在单个链表。您必须删除一个节点。您需要编写一个删除该节点的函数,该节点仅删除要删除的节点的地址作为输入而不包含其他内容(包括头)“

我给出了类似于下面帖子中回答的答案 - 将下一个节点的内容复制到要删除的节点中并删除下一个节点。

Deleting a middle node from a single linked list when pointer to the previous node is not available

但是面试官再次问我,如果我传递最后一个节点的地址怎么办?我告诉他,因为下一个将是一个NULL,将NULL复制到数据字段以及下一个节点的地址也是NULL。然后他告诉我将会出现悬挂指针的问题......我对此并不了解。请问有人可以解决这个问题吗?有没有通用的解决方案呢?

更新(两天后):再补充一点。考虑到列表末尾没有特殊节点。最后一个节点指向NULL,如果该节点作为输入,则如何使前一个节点指向NULL。或者这是不可能的?

简单地说:如果一个节点作为函数的输入,如何使引用它的指针,指向NULL

7 个答案:

答案 0 :(得分:13)

步骤:

  1. 将数据从节点(i + 1)复制到节点(i)
  2. 将第二个节点(i + 1)的NEXT复制到临时变量中。
  3. 现在删除第二个节点(i + 1)//它不需要指向前一个节点的指针。
  4. 功能:

    void delete_node(node* node)
    {
        node->Data = node->Next->Data;
        node* temp = node->Next->Next;
        delete(node->Next);
        node->Next = temp;
    }
    

答案 1 :(得分:9)

悬空指针:

  

(http://en.wikipedia.org/wiki/Dangling_reference)

     

计算机编程中的悬空指针和狂野指针是   指向不指向适当类型的有效对象的指针。   这些都是违反记忆安全的特殊情况。

     

删除或取消分配对象时会出现悬空指针,   无需修改指针的值,使指针仍然存在   指向释放的内存的内存位置。作为系统   可以将以前释放的内存重新分配给另一个进程,如果是   原始程序然后取消引用(现在)悬空指针,   可能导致不可预测的行为,因为内存现在可能包含   完全不同的数据。

在您的回答中,要删除给定节点,您实际上删除了 next 节点,该节点可能被指针引用。这就是悬垂指针问题出现的原因。

(1)正如您在备注中说明的那样,没有外部参考列表。 (2)面试官说,可能会出现悬垂指针问题。

(1)和(2)都不能同时正确。这意味着某处存在误解。

关于删除最后一个节点:

  

但是面试官再次问我,如果我通过该地址,该怎么办?   最后一个节点我告诉他,因为下一个将是NULL,复制那个NULL   进入数据字段以及到下一个节点的地址   也是NULL。

我认为你混淆了这两件事:(1)指向NULL的指针p,(2)在其数据字段中具有NULL的链表节点。

假设数据结构为a -> b -> c -> d。将NULL写入d's数据字段不会使c在其next字段中具有NULL指针。

如果链接列表始终具有永不删除的特殊最后一个节点,则可以删除最后一个节点。例如,a -> b -> c -> d -> LAST其中LAST在其数据字段中有一个特殊值,表示它实际上是最后一个元素。现在要删除d,你可以删除LAST并在d's数据字段中写入特殊值。

也许这些正是你在面试中试图说的,在这种情况下,你和面试官之间肯定会有一些误解。

答案 2 :(得分:3)

然后应该在程序中检查给定节点是否是最后一个节点。

void delete_node(node* node1)
{
    node* search=head;
    if(node1==head)
    {
        head=head->next;
        search->next=NULL;
        node1->next=NULL;
    }
    while(search->next != node1)
        search=search->next;
    if(node1->next==NULL)
    {
       search->next=NULL;
    }
    else
    {
       search->next=node1->next;
       node1->next=NULL;
    }
    delete node1;
}

答案 3 :(得分:2)

如果有其他元素指向将被复制到当前节点然后删除的下一个节点,则此操作将引入错误。因此,在您的回答中,您应该强调,只有在没有外部引用列表的情况下,您的解决方案才有效。

只有在使用特定的“最后一个节点”元素扩充数据结构时,您的解决方案才能使用最后一个节点。 (如果您使用的是Smalltalk,则可以编写self become: nil没有其他语言有类似的内容)

不,如果列表有外部引用,则没有通用解决方案。我认为面试官想知道你是否真的知道这个主题,或者只是重复一个记忆的答案。

答案 4 :(得分:1)

可能您的链接列表遍历可能需要假设任何指向null的节点都是null节点,而不管其值是什么...

a->b->c->d->NULL

所以dnull节点,不应将该节点视为节点。这样你可以节省使用特殊值,因为它们在一般意义上是不正确的。除此之外,您将没有任何其他方式让前一个节点指向null

答案 5 :(得分:0)

 public void removeNode(Node node){

        /* if no node return null */
        if(node==null) return;

        /* if only 1 node then delete node */
        if(node.getNext()==null) {
            node = null;
            return ;
        }

        /* copy next node data to this node */
        node.data = node.getNext().data();

        /* store the next next node */
        Node second = node.getNext().getNext();

        /* remove next node */
        removeNode(node.getNext());

        /* set the copied node as next */
        node.setNext(second);
     }

答案 6 :(得分:0)

假设:deleteNode() 引用了节点指针。

没有while循环的简单解决方案。在deleteNode()中,if case处理头节点和中间节点的删除,else处理最后一个节点的删除。

#include <iostream>
using namespace std;

class Node{

public:
  int data;
  Node* next;

  Node(int d): data(d){}
};

void insert(Node* &head,  int data){
  Node *node = new Node(data);
  node->next = head;
  head = node;
}

void print(Node *head){
  Node *temp = head;
  while(temp !=NULL){
    cout << temp->data <<" ";
    temp = temp->next;
  }
  cout << endl;
}

void deleteNode(Node *&node){

  cout << "Deleting "<<node->data<<endl;
  if(node->next != NULL){
    Node *t = node->next;
    node->data = node->next->data;
    node->next = node->next->next;

    delete t;
  }else{
    delete node;
    node = NULL;
  }
}

int main(int argc, char const *argv[]) {

  Node *head = NULL;
  insert(head, 10);
  insert(head, 20);
  insert(head, 30);
  insert(head, 40);
  insert(head, 50);

  print(head);

  deleteNode(head->next); //delete 40
  deleteNode(head->next->next->next); //delete last node 10

  print(head);

  return 0;
}