首页 文章

从Linked-list弹出

提问于
浏览
4

我在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 不会删除对第一个节点的引用 . (即,当我打印列表时,第一个节点仍在那里) .

谢谢 .

4 回答

  • 3

    您需要为您的函数传递 head 的地址以进行修改 . 然后你的函数需要取消引用这个地址 . 此外,最后一个pop()也需要更改* AddressOfHead

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

    ...

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

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

    if (*head != NULL) ...
    

    接下来,将指针传递给指针将起作用 . 但实际上制作这样的列表 Headers 更好:

    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 一个指针,这会消除很多 & 's in your code. Then it'以实现推送和弹出:

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

    注意,不需要更改调用代码 . 随着指针接近指针,你处于死胡同 . 还有许多其他用例,其中具有单独的列表 Headers 使您的代码更灵活,以便将来进行更改 .

  • 1

    其他人告诉你如何解决它,让我回答为什么 temp 改变了..

    Node * pop (Node * head) {
    

    您正在传递 head 作为指向 Node 的指针 .

    因此,当你这样做

    *head = *head->next;
    

    我认为它被解析为

    *head = *(head->next);
    

    因此,在 head 处将下一个对象复制到对象中,该对象在 temp 处是同一个对象 .

  • 1

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

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

    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 的值在原始代码中发生了变化 .

相关问题