【问题标题】:Why to return pointer after inserting node in Link Lists为什么在链接列表中插入节点后返回指针
【发布时间】:2015-05-30 05:15:26
【问题描述】:

我不明白为什么我们必须在将节点添加到链表后返回指向头节点的指针。

struct node *append(int v) {
    struct node *ptr;
    struct node *t;
    ptr=head;
    while (ptr->next != tail) ptr = ptr->next;
    t=(struct node *) malloc(sizeof *t);
    t->value=v;
    t->next = tail;
    ptr->next = t;
    return ptr; // why return ptr?
}

【问题讨论】:

  • 我认为您必须对上下文进行更多解释才能得到答案。
  • 这里没有返回“指向头节点的指针”;那一定是一个外部变量,所以不需要返回。您正在返回一个指向插入节点之前的节点的指针。根据您的要求,它可用于撤消附加和其他操作。

标签: c pointers linked-list


【解决方案1】:

这取决于您的问题的上下文。通常在链表问题中,你必须返回链表的头部,这样你的数据结构才能保持一致,但我从你的代码中推断出头部是一个全局变量。

除非调用此函数的代码需要知道创建的新节点的位置,否则您不需要返回该节点,因为您的 head 是一个全局变量(同样,如果我的假设是正确的)。

除此之外,我建议修改你的函数,因为我看到你在这里遗漏了一些情况(如果列表为空,例如你必须改变头部怎么办?)

【讨论】:

    【解决方案2】:

    首先功能无效。当列表为空并添加第一个元素时,head 可以等于NULL。所以使用函数代码中对应ptr->next的表达式head->next会导致内存访问冲突。

    在我看来,将NULL 命名为tail 也不是一个好主意。我会明确使用NULL。否则代码会混淆读者。

    永远的函数可以如下所示

    struct node * append( int v ) 
    {
        struct node *t = ( struct node * )malloc( sizeof( *t ) );
        t->value = v;
        t->next  = tail;
    
        if ( head == tail )
        {
            head = t;
        }
        else
        {
            struct node *current = head;
            while ( current->next != tail ) current = current->next;
            current->next = t;
        }
    
        return t;
    }
    

    至于你的问题,我也不明白为什么函数返回ptr 而不是t。它应该返回t。在这种情况下,函数会更加正确和高效,因为它会在第一个元素附加到空列表时返回 head 并且当下一个非第一个值附加到列表时,head 将是某个节点(不需要head 本身)while 循环没有迭代,因为第一个表达式 ptr->next 已经等于 NULL。

    该函数应该返回最后一个附加的节点,如我所展示的实现。

    我确定这只是函数设计中的错误。:)

    如果不在函数内使用全局变量head,而是将其声明为函数参数,这个缺点会更加明显。例如

    struct node * append( struct node *head, int v ) 
    {
        struct node *t = ( struct node * )malloc( sizeof( *t ) );
        t->value = v;
        t->next  = tail;
    
        if ( head == tail )
        {
            head = t;
        }
        else
        {
            struct node *current = head;
            while ( current->next != tail ) current = current->next;
            current->next = t;
        }
    
        return t;
    }
    

    在这种情况下,main 中的函数调用可能如下所示

    struct node *head = NULL;
    
    struct node *current;
    int i;
    
    head = append( head, 0 );
    
    for ( i = 1, current = head; i < 10; i++ ) current = append( current, i ); 
    

    在这种情况下,append 的调用将非常有效,因为在函数内,while 循环甚至不会进行一次迭代。

    【讨论】:

      【解决方案3】:

      当列表为空时,链表通常使用 NULL 头来实现。在这种情况下,当头部是局部变量时,或者当它是全局变量并且您希望使用相同的函数拥有多个列表时,您必须返回列表的头部。添加节点时,头部可能已经改变,即使在尾部添加,如果列表为空,则会有一个新的头部。

      但另一种方法是始终在头部有一个节点,只是在这里表示头部,并在此头部之后添加/读取/删除节点以处理列表中的数据。在这种情况下,返回头部是没有用的,因为头部永远不会改变。

      您可以在节点 n:n-&gt;next == NULL 时检测列表的尾部,当列表为空时使用等于 NULL 的头部,如下代码所示:

      // add at the tail of the list:
      struct node * add_to_list_tail(struct node * head,int v) {
        struct node *t;
        t=(struct node *) malloc(sizeof(struct node));
        t->value = v;
        t->next = NULL; // next is set to NULL because it is the new tail
      
        if(head == NULL) {
          // in the case the list is empty
          head = t; // t become the new head, because the list was empty
        } else {
          // in the case the list isn't empty
          struct node * n = head;
          // the following loop will stop when n->next == NULL, and n will point to the tail
          while(n->next != NULL) {
            n = n->next;
          }
          n->next = t;
        }      
        return head;
      }
      
      // add at the head of the list:
      struct node * add_to_list(struct node * head,int v) {
          struct node *t;
          t=(struct node *) malloc(sizeof(struct node));
          t->value = v;
          t->next = head; // make t become the new head
          return t; // return t because it is the new head
      }
      
      int main() {
        struct node * head = NULL;
        head = add_to_list(head,1);
        head = add_to_list(head,2);
        head = add_to_list_tail(head,3);
      }
      

      如果你不想返回头部,你也可以传递一个指向头部指针的指针,作为操作列表的函数的参数。一个简短的示例代码:

      void add_to_list(struct node ** head,int v) {
          struct node *t;
          t=(struct node *) malloc(sizeof(struct node));
          t->value = v;
          // make t become the new head:
          t->next = *head;
          *head = t;
      }
      
      int main() {
        struct node * head = NULL;
        // we pass &head, the adress of variable head, as parameter:
        add_to_list(&head,1);
        add_to_list(&head,2);
      
        struct node * n = head;
        while(n != NULL) {
          printf("\nvalue: %d",n->value);
          n = n->next;
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-15
        • 2021-12-02
        • 1970-01-01
        相关资源
        最近更新 更多