【问题标题】:Mergesort on a linked-list using only one function, segmentation fault仅使用一个函数对链表进行合并排序,分段错误
【发布时间】:2015-02-17 17:13:32
【问题描述】:

我需要实现的功能:struct listnode * mergesort(struct listnode *data) 我的教授提供了 main() 函数测试代码。我只需要提交合并排序功能。他告诉我们用 C 或 C++ 来做,但他给我们的测试代码 main() 是用 C 写的。

这是我现在的代码: 我可以编译它,但是当我运行它时,它会崩溃。我检查了调试器,它给了我分段错误。我也不确定这个函数是否正确,因为我无法通过 main() 中的测试点。


#include <stdio.h>
#include <stdlib.h>

struct listnode { struct listnode * next;
                         long              value; } ;


struct listnode * mergesort(struct listnode *data)
{   int temp, finished = 0;
    struct listnode *tail, *head, *ahead, *bhead, *atail, *btail;
    if ( data == NULL )
        return;
    //Split
    ahead = atail = head = data;       // first item
    btail = head->next;         // second item
    while(btail->next != NULL)  // anything left
    {
    atail = atail->next;
    btail = btail->next;
    if( btail->next != NULL)
        btail = btail->next;
    }
    bhead = atail->next;        // disconnect the parts
    atail->next = NULL;

    //sort
    mergesort(ahead);
    mergesort(bhead);

    //merge
    if(ahead->value <= bhead->value)  // set the head of resulting list
        head = tail = ahead, ahead = ahead->next;
    else
        head = tail = bhead, bhead = bhead->next;

    while(ahead && bhead)
        if(ahead->value <= bhead->value)  // append the next item
            tail = tail->next = ahead, ahead = ahead->next;
        else
            tail = tail->next = bhead, bhead = bhead->next;

    if(ahead != NULL)
        tail->next = ahead;
    else
        tail->next = bhead;
    return(head);
}


int main(void)
{
   long i;
   struct listnode *node, *tmpnode, *space;
   space =  (struct listnode *) malloc( 500000*sizeof(struct listnode));
   for( i=0; i< 500000; i++ )
   {  (space + i)->value = 2*((17*i)%500000);
      (space + i)->next = space + (i+1);
   }
   (space+499999)->next = NULL;
   node = space;
   printf("\n prepared list, now starting sort\n");
   node = mergesort(node);
   printf("\n checking sorted list\n");
   for( i=0; i < 500000; i++)
   {  if( node == NULL )
      {  printf("List ended early\n"); exit(0);
      }
      if( node->value != 2*i )
      {  printf("Node contains wrong value\n"); exit(0);
      }
      node = node->next;
   }
   printf("Sort successful\n");
   exit(0);
}

【问题讨论】:

  • 打开编译器警告并处理它们!! if ( data == NULL) return; 必须返回一个值。而mergesort(ahead); mergesort(bhead); 则忽略返回的值。
  • 啊,是的!有人告诉我,仅仅做mergesort(ahead); mergesort(bhead); 是行不通的,但我不确定如何让它返回新列表的头部。有人可以告诉我我应该怎么做吗?
  • 首先你应该有 |提前 = 合并排序(提前); | , | bhead = 合并排序(bhead); | .接下来,您需要清理合并代码。使用指向指针的指针可以简化创建合并列表: |节点 * pNew = NULL; | , |节点**ppNew = &pNew; | ,然后设置 *ppNew = 指向两个节点中较低节点的指针,并使用 | 推进 ppNew ppNew = &((*ppNew)->next); .下一个指向两个节点中较低节点的指针 = *ppNew;
  • @rcgldr 谢谢,我现在有了 ahead = mergesort(ahead) 和 bhead = mergesort(bhead)。还有,我很抱歉!我在编码方面非常业余,所以对于你所说的关于指针指针的事情,我不确定你是否可以澄清一下,因为我不太明白。现在,我无法弄清楚if(data != NULL) ahead = atail = head = data; if(head-&gt;next !=NULL){ btail = head-&gt;next; } if(btail != NULL) while(btail-&gt;next != NULL) 调试器在while(btail-&gt;next != NULL) 处不断给我一个错误
  • @Jia - 有关合并列表的示例功能,请参见下面的答案。我没有经历多次重复的答案和问题,而是使用指向指针的指针发布了合并列表部分的示例代码。

标签: c sorting linked-list mergesort


【解决方案1】:
if ( data == NULL )
    return;

你应该返回 NULL。


btail = head->next;         // second item
while(btail->next != NULL)  // anything left
{

如果 btail 设置为 head->next。如果 head->next 为 NULL,则您正在尝试检查循环 NULL->next != NULL 这不是一个东西。


if( btail->next != NULL)
    btail = btail->next;
}

在检查 -> 下一步之前,您需要检查 btail 是否为 NULL。就在你上面设置 btail = btail->next;所以它可以设置为NULL。

上面的循环也有同样的问题,你需要在使用 next 之前检查 null。


下面的代码可能有问题,但上面的代码需要更多的错误检查。

【讨论】:

  • 所以我做了if(head-&gt;next !=NULL){ btail = head-&gt;next; // second item }if(btail != NULL) while(btail-&gt;next != NULL) // anything left { 但是调试器仍然在while循环中给我一个错误,即使我检查了btail != NULL
  • 抱歉回复晚了。您需要检查是否 head != NULL,然后检查 head->next != NULL。
【解决方案2】:

使用指向指针的指针合并两个已排序列表的示例函数。由于您只允许一个函数,因此您必须将此逻辑合并到您的 mergesort() 函数中。如果这是家庭作业,您可能会得到太多帮助,但我不确定如何解释此示例中显示的想法。

NODE * MergeLists(NODE *pSrc1, NODE *pSrc2)
{
NODE *pDst = NULL;                      /* destination head ptr */
NODE **ppDst = &pDst;                   /* ptr to head or prev->next */
    while(1){
        if(pSrc1 == NULL){
            *ppDst = pSrc2;
            break;
        }
        if(pSrc2 == NULL){
            *ppDst = pSrc1;
            break;
        }
        if(pSrc2->data < pSrc1->data){  /* if src2 < src1 */
            *ppDst = pSrc2;
            pSrc2 = *(ppDst = &(pSrc2->next));
            continue;
        } else {                        /* src1 <= src2 */
            *ppDst = pSrc1;
            pSrc1 = *(ppDst = &(pSrc1->next));
            continue;
        }
    }
    return pDst;
}

【讨论】:

  • 一个函数可以在另一个函数中创建吗?例如,是否可以在 struct listnode * mergesort(struct listnode *data) 内创建一个合并列表函数?
  • 你可以做一个宏,但由于声明的目标是一个单一的功能,这可能被认为是违反规则的。您可以在现有函数中使用类似的代码,对 pSrc1 使用 ahead,对 pSrc2 使用 bhead,对合并列表使用 pDst/ppDst 或 pNew/ppNew。
猜你喜欢
  • 2021-07-14
  • 1970-01-01
  • 1970-01-01
  • 2021-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-19
相关资源
最近更新 更多