为什么在链接列表中插入节点后返回指针

时间:2015-05-30 05:15:26

标签: c pointers linked-list

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

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

3 个答案:

答案 0 :(得分:0)

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

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

除此之外,我建议修改你的功能,因为我看到你在这里丢失的一些情况(如果列表为空而你必须改变头部怎么办?)

答案 1 :(得分:0)

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

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

对于节点n:n->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;
  }
}

答案 2 :(得分:0)

首先功能无效。当列表为空并且添加了第一个元素时,head可以等于NULL。因此,使用函数代码中对应head->next的表达式ptr->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本身)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循环甚至不会进行一次迭代。