【问题标题】:Deleting any node from a single linked list when only pointer to that node is given当仅给出指向该节点的指针时,从单个链表中删除任何节点
【发布时间】:2012-03-10 21:32:57
【问题描述】:

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

"内存中有一个单链表,你必须删除一个节点,你需要写一个函数来删除那个节点,它只需要将要删除的节点的地址作为输入,没有其他内容(包括头)”

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

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

但是面试官又问我,如果我通过最后一个节点的地址怎么办。我告诉他,因为下一个将是 NULL,所以将该 NULL 连同地址一起复制到数据字段中,下一个节点也是 NULL。然后他告诉我会有一个悬空指针的问题......我有点不明白。有人可以解决这个问题吗?有没有通用的解决方案?

更新(两天后):增加一点。考虑到列表末尾没有特殊节点。最后一个节点指向 NULL,如果该节点作为输入给出,如何使最后一个节点指向 NULL。还是不可能?

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

【问题讨论】:

  • 你问什么是悬空指针问题?或者如何解决?
  • 两者,其实我也想知道悬空指针..

标签: data-structures linked-list


【解决方案1】:

步骤:

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

功能:

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

【讨论】:

    【解决方案2】:

    悬空指针:

    (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 的数据字段不会神奇地使 c 在其 next 字段中具有 NULL 指针。

    你可以删除最后一个节点如果链表总是有一个永远不会被删除的特殊最后一个节点。例如,a -> b -> c -> d -> LAST,其中 LAST 在其数据字段中有一个特殊值,表示它实际上是最后一个元素。现在要删除 d,您可以删除 LAST 并将特殊值写入 d 的数据字段。

    也许这些正是你在面试中试图表达的,在这种情况下,你和面试官之间一定存在沟通不畅。

    【讨论】:

    • 感谢 wiki 并让我了解悬空指针问题。关于陈述(1),确实没有外部参考。指向我们要删除的节点的唯一节点是当前节点。由于我们正在将下一个(即要删除的节点)的内容复制到当前节点,所以现在没有人指向要删除的节点。因此,当我们删除它时,不会出现悬空指针问题。这一点很清楚。关于最后一个节点,让我在单独的段落中稍微编辑一下我的问题
    • 这是我对您更新后的问题的回答:这是不可能的。如果您需要第二意见,也许您应该将其作为一个新问题发布。
    【解决方案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;
    }
    

    【讨论】:

      【解决方案4】:

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

      只有在数据结构中增加了特定的“最后一个节点”元素时,您的解决方案才适用于最后一个节点。 (如果你用的是Smalltalk,可以写self become: nil没有其他语言有类似的)

      不,如果有对列表的外部引用,则没有通用解决方案。我想面试官想看看你是否真的对这个主题很了解,或者只是在重复一个记住的答案。

      【讨论】:

      • 这是一个单链表,也没有外部引用。我的问题是关于尝试复制最后一个节点时可能出现的 NULL 指针引用问题。另外,请注意,在单个链表中,最后一个节点指向 NULL
      【解决方案5】:

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

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

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

      【讨论】:

        【解决方案6】:

        当给出最后一个节点时,不要删除它,而是将其分配给一个虚拟节点,在显示数据时,我们可以检查 ptr->next 作为虚拟节点并在那里终止。

        如果是悬空指针,我相信当指针被释放(释放)时,它会变成悬空指针,所以在释放后将它分配给NULL。

        下面是我的代码 sn-p 这个问题:

        dummy-> data = NULL;
        dummy-> next = NULL;
        FUNC(del_ptr)
        {
        if (del_ptr->next == NULL )
        {
        del_ptr = dummy;
        return;
        }
        struct node *next = del_ptr ->next;
        del_ptr -> data = next -> data;
        del_ptr -> next = next -> next;
        free(next);
        next=NULL;
        }
        

        【讨论】:

          【解决方案7】:

          假设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;
          }
          

          【讨论】:

            【解决方案8】:
            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);
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2010-09-09
              • 1970-01-01
              • 1970-01-01
              • 2013-06-15
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多