【问题标题】:How to pop from linked list?如何从链表中弹出?
【发布时间】:2013-08-29 15:36:50
【问题描述】:

我在 C 中实现了一个带有 Pop 函数的 Linked-List:

Node * pop (Node * head) {
    Node * temp = head;

    printf("Temp is: %s\n", temp->val);

    if (head->next != NULL) {
        *head = *head->next;
    }

    printf("Temp is: %s\n", temp->val);
    return temp;
}

当我弹出时的输出会是这样的:

Temp is: node1 value
Temp is: node2 value

也就是说,当我分配*head = *head->next时,temp变成了temp->next。

那么如何获取当前head 的值并将其返回,同时还将链接列表的头部移动到head->next

执行head = head->next 不会删除对第一个节点的引用。 (即当我打印列表时,第一个节点仍然存在)。

【问题讨论】:

    标签: c pointers linked-list return


    【解决方案1】:
    void pop(struct node** tol) {
      struct node* t = *tol;
      while (t->link->link != NULL){
        t = t->link;    
      }
      t->link = NULL;
    }
    

    【讨论】:

      【解决方案2】:

      指针按值传递。也就是说,当您将指针传递给堆栈时,被调用函数对指针指向的内容的更改不会反映在调用函数中。

      为了在调用函数中改变节点指针的值,需要将栈作为指向指针的指针传递:

      Node* pop (Node** head) {
      
          Node* temp = *head;    
      
          if (temp) {
             *head = temp->next;    // to update stack in calling function
             temp->next = NULL;     // to detach temp from the rest of the list
          }
      
          return temp;
      }
      

      在更新*head 的值之前,您不需要检查if ((*head)->next) 或在本例中为if (temp->next),因为如果您位于堆栈的最后一个节点并且下一个节点是NULL,您想要无论如何,列表是NULL

      Karthik T 的答案正确解释了为什么 temp 的值在您的原始代码中发生了变化。

      【讨论】:

        【解决方案3】:

        首先,请注意您的代码(以及之前的一些解决方案)永远不会弹出列表中的最后一个元素。你想要的

        if (*head != NULL) ...
        

        接下来,将指针传递给指针将起作用。但实际上最好是这样制作一个列表标题:

        typedef struct node_s {
          struct node_s *next;
          ... data declaration here
        } Node;
        
        typedef struct list_s {
          struct node_s *head;
        } List;
        
        void init_list(List *list) {
          list->head = NULL;
        }
        

        现在声明一个这样的列表:

        List list[1];
        
        init_list(list);
        

        声明一个包含一个元素的数组会使每个对list 的引用自动成为一个指针,从而消除代码中的大量&。那么实现push和pop就很干净了:

        void push(List *list, Node *node) {
          node->next = list->head;
          list->head = node;
        }
        
        Node *pop(List *list) {
          Node *head = list->head;
          if (head) {
            list->head = head->next;
            head->next = NULL;
          }
          return head;
        }
        

        为什么这样更好?假设您稍后决定保留列表中的项目计数。使用单独的标头节点,这很容易:

        typedef struct list_s {
          struct node_s *head;
          int length;
        } List;
        
        void init_list(List *list) {
          list->head = NULL;
          length = 0;
        }
        
        void push(List *list, Node *node) {
          node->next = list->head;
          list->head = node;
          ++list->length;
        }
        
        Node *pop(List *list) {
          Node *head = list->head;
          if (head) {
            list->head = head->next;
            head->next = NULL;
            --list->length;
          }
          return head;
        }
        

        请注意,无需更改调用代码。使用指向指针方法的指针,您处于死胡同。还有许多其他用例,其中具有单独的列表标题可以使您的代码更灵活地适应未来的变化。

        【讨论】:

          【解决方案4】:

          您需要将head 的地址传递给您的函数来修改它。然后你的函数需要取消引用这个地址。此外,最后一个 pop() 也需要更改 *AddressOfHead

          Node *pop(Node **AddressOfHead) {
              Node *temp = *AddressOfHead;
              if (temp) {
                  *AddressOfHead = temp->next;
              }
              return temp;
          }
          

          ...

          // Usage example
          Node *TopOfList = pop(&Head);
          

          【讨论】:

          • @Travv92 仔细测试。如果您从 NULL 头开始并推送节点,这将永远不会弹出最后一个节点。
          • @Gene 你能解释一下为什么会发生这种情况吗?我这里有一些代码确实可以正确弹出最后一个节点:ideone.com/tVYck0。 (请忽略我没有释放分配的内存的事实)
          • @verbose 有人解决了这个问题!现在好了。我仍然认为使用指针指向指针而不是真正的列表头会使代码变脆。
          • @Gene 的优缺点。拥有 Head 结构可能很有用。如果需要的不仅仅是非零值,那么具有长度的头部结构可以提供快速的长度评估。对于其他标记信息也很有用。带有长度的头结构是多余的,因为列表以 NULL 结尾并且一致性成为一个问题。带长度的头部占用 2 倍空间。当可能存在大量空列表时,这很重要。顺便说一句:我儿子最近在平原上度过了一天。
          • @chux 好的,但是四个字节很少是决定性的,而将大量列表操作更改为新的约定通常是。如果你喜欢无头列表,你应该使用循环,外部指针 P 指向尾部,所以 P->next 是头部。然后你可以免费排队。恭喜你的普莱贝。我们可能有他在 IT105。如果没有,那就下学期。
          【解决方案5】:

          别人已经告诉你怎么解决了,让我来回答为什么temp变了..

          Node * pop (Node * head) {
          

          您将 head 作为指向 Node 的指针传递。

          所以当你这样做时

          *head = *head->next;
          

          我认为它被解析为

           *head = *(head->next);
          

          因此将 next 中的对象复制到 head 的对象中,这当然是 temp 的同一个对象。

          【讨论】:

          • 你“想”?所以,你不确定你在回答什么。
          猜你喜欢
          • 1970-01-01
          • 2013-11-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-10-19
          • 1970-01-01
          • 2021-01-22
          • 2012-04-27
          相关资源
          最近更新 更多