过滤链表并返回新的链表 C

Posted

技术标签:

【中文标题】过滤链表并返回新的链表 C【英文标题】:Filter linked list and return new linked list C 【发布时间】:2015-10-01 03:51:01 【问题描述】:

我正在尝试过滤链接列表。由于我不想更改原始链表,因此我想创建一个子链表并返回它。

我遇到了麻烦,因为我只知道如何从过滤过程中获取 1 个节点,但我不知道如何移动并将节点从原始链表添加到子链表。

我有一个这样的结构(这表示哈希表中的一个条目):

typedef struct Entry 
   char *word;
   int len;
   struct Entry *next;
 Entry;

我的过滤函数将接收单词长度和原始链表作为参数,然后查找具有相同 len 值的节点。每当它找到一个具有相同 len 值的节点时,它就会将该节点添加到另一个链表中。最后返回新的链表。

struct Entry* filterLen(int len, struct Entry *en) 
   struct Entry *temp = (struct Entry *)malloc(sizeof(struct Entry));

   while(en->next != NULL) 
      if (en->len == len) 
         // assign values to temp list
         temp->word = en->word;
         temp->len = en->len;
         temp->next = en;
      

      en = en->next; // move through list
   

   return temp;

【问题讨论】:

问题出在哪里? 你已经有了旧的链表,所以大概你也已经有了将条目添加到链表的通用代码。因此,使用该代码将新的克隆条目添加到 new 链接列表。 【参考方案1】:
Entry* filterLen(int len, Entry *en) 
   Entry *result = NULL, **temp = &result;

   while(en != NULL) 
      if (en->len == len) 
     // assign values to temp list
         *temp = malloc(sizeof(Entry));
         (*temp)->word = en->word;
         (*temp)->len = en->len;
         (*temp)->next = NULL;
         temp = &((*temp)->next);
      

      en = en->next; // move through list
  

  return result;

编辑 这里似乎是一场比赛,所以:

Entry* filterLen(int len, Entry *en) 
   Entry *result, **temp = &result;

   for ( ; en; en = en->next)  // Move through list
      if (en->len == len)         // Then assign values to temp list
         *temp = malloc(sizeof(Entry));
         (*temp)->word = en->word; // WARNING str shared with en list!!!
         (*temp)->len = en->len;
         temp = &((*temp)->next);
      
   
   *temp = NULL;
   return result;

【讨论】:

这段代码如何能够在结果中返回超过 1 个节点?我看不到节点的链接。更不用说如果多个节点匹配会发生内存泄漏(由于悬空指针)。 @AlanAu 只是忘记了一行。固定的。谢谢 @MikkelChristiansen 仅供参考,您可以在循环中去掉(*temp)->next = NULL;,然后在return 语句之前执行*temp = NULL;。而且您可能需要深度复制word 成员,顺便说一句。然而,从 OP 的帖子中,这一点并不完全清楚。 @WhozCraig 我知道,但这更接近原版。【参考方案2】:

根据我对您问题的理解,您希望返回条目的链接列表,其中 len 字段等于输入参数。目前,您的代码仅存储一个“临时”,您需要重新构建一个新列表。

struct Entry* filterLen(int len, struct Entry *en) 
  struct Entry *first = NULL;
  struct Entry *last = NULL;
  while(en != NULL) 
    if (en->len == len) 
      if(last)
        last->next = (struct Entry *)malloc(sizeof(struct Entry));
        last = last->next;
       else 
        last = (struct Entry *)malloc(sizeof(struct Entry));
        first = last;
      
      // assign values to temp list
      last->word = en->word;
      last->len = en->len;
      last->next = NULL;
    
    en = en->next; // move through list
  
  return first;

【讨论】:

您的 while 条件错误。它应该是 while(en != NULL)。你返回的是什么? 你说得对,我重用了原代码的一部分,忘记改错误的while循环了。【参考方案3】:
Entry* filterLen(int len, Entry *en) 
    Entry result =  NULL, 0, NULL ;
    Entry *curr  = &result;

    while(en != NULL)
        if(en->len == len)
            Entry *temp = malloc(sizeof(*temp));
            *temp = *en;
            temp->next = NULL;
            curr = curr->next = temp;
        
        en = en->next;
    
    return result.next;

【讨论】:

【参考方案4】:

现在,您的过滤函数正在将它找到的最后一个节点的内容(包括next 指针)复制到temp 节点中。这导致函数返回最后一个匹配节点加上列表中它之后的任何内容。

您需要做的是每次找到匹配节点时创建一个新节点并将内容复制到该节点。这包括复制字符串,因此您不必担心可能会双重释放任何内容。

struct Entry* filterLen(int len, struct Entry *en) 
   struct Entry *result = NULL, *temp = NULL;

   while(en != NULL) 
      if (en->len == len) 
         // copy node to end of temp list
         if (temp == NULL) 
             result =  malloc(sizeof(struct Entry));
             temp = result;
          else 
             temp->next =  malloc(sizeof(struct Entry));
             temp = temp->next;
         
         temp->word = strdup(en->word);  // Perform a deep copy
         temp->len = en->len;
         temp->next = NULL;
      

      en = en->next; // move through list
   

   return result;

【讨论】:

以上是关于过滤链表并返回新的链表 C的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 21.合并两个有序链表

剑指 Offer 25. 合并两个排序的链表

有序链表合并

21. 合并两个有序链表

LeetCode刷题之合并排序链表

剑指offer-合并两个排序的链表