在链接列表上实现mergesort

时间:2016-02-24 22:03:03

标签: c algorithm sorting linked-list mergesort

我的任务是在用C / C ++编写的列表上实现合并排序算法。我有一般的想法,编写我的代码并成功编译它。然而,当我运行它时,它会开始正常,但然后挂在"准备好的列表,现在开始排序"没有给出任何错误。我试图查看我的代码,但我完全不知道问题是什么。我也非常业余的调试,所以使用gdb尽我所能导致我没有在哪里。任何建议或提示都将是一个巨大的帮助,谢谢大家!

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

struct listnode
{
    struct listnode *next;
    int key;
};

    //Finds length of listnode
int
findLength (struct listnode *a)
{
    struct listnode *temp = a;
    int i = 0;
    while (temp != NULL)
    {
        i++;
        temp = temp->next;
    }
    return i;
}


struct listnode *
sort (struct listnode *a)
{
    // Scenario when listnode is NULL
    if (findLength (a) <= 1)
        return a;

    //Find middle
    int mid = findLength (a) / 2;
    struct listnode *temp = a;
    struct listnode *first = a;
    struct listnode *second;

    for (int i = 0; i < mid - 1; i++)
    {
        temp = a->next;
    }
    second = temp->next;
    temp->next = NULL;

    //Recursive calls to sort lists
    first = sort (first);
    second = sort (second);

    if (first != NULL && second != NULL)
    {
        if (first->key < second->key)
        {
            a = first;
            first = first->next;
        }
        else
        {
            a = second;
            second = second->next;
        }
    }

    struct listnode *head = a;
    struct listnode *tail = a;

    while (first != NULL && second != NULL)
    {
        if (first->key < second->key)
        {
            tail = first;
            first = first->next;
            tail = tail->next;
        }
        else
        {
            tail = second;
            second = second->next;
            tail = tail->next;
        }
    }

    if (first == NULL)
    {
        while (second != NULL)
        {
            tail = second;
            second = second->next;
            tail = tail->next;
        }
    }

    while (first != NULL)
    {
        tail = first;
        first = first->next;
        tail = tail->next;
    }

    return a;
}

这是提供的测试代码,用C: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)->key = 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 = sort (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->key != 2 * i)
        {
            printf ("Node contains wrong value\n");
            exit (0);
        }
        node = node->next;
    }
    printf ("Sort successful\n");
    exit (0);
}

2 个答案:

答案 0 :(得分:0)

它必须是自上而下的合并排序吗?为了让你开始,这是一个部分修复,没有检查其他东西。 | if(first!= NULL&amp;&amp; second!= NULL)|由于事先检查了长度&lt; = 1,因此不需要检查,但它不会导致问题。

    while (first != NULL && second != NULL)
    {
        if (first->key < second->key)
        {
            tail->next = first;
            tail = first;
            first = first->next;
        }
        else
        {
            tail->next = second;
            tail = second;
            second = second->next;
        }
    }

    if (first == NULL)
    {
        tail->next = second;
    }
    else
    {
        tail->next = first;
    }
}

答案 1 :(得分:0)

你很亲密,但有一些愚蠢的错误。检查合并步骤中的追加操作。他们没有做你认为他们的事。当然,在分裂循环中你的意思是temp = temp->next;

如果gdb压倒性的话,添加printf是一个非常好的方法来调试这样的代码。实际上,您希望编写列表打印功能并在每个递归级别打印子列表以及合并步骤的结果。看起来很有趣。只需要整洁,并在完成后删除所有内容。

以下代码可供参考:

struct listnode *sort(struct listnode *lst) {
  if (!lst || !lst->next) return lst;
  struct listnode *q = lst, *p = lst->next->next;
  while (p && p->next) {
    q = q->next;
    p = p->next->next;
  }
  struct listnode *mid = q->next;
  q->next = NULL;
  struct listnode *fst = sort(lst), *snd = sort(mid);
  struct listnode rtn[1], *tail = rtn;
  while (fst && snd) {
    if (fst->key < snd->key) {
      tail->next = fst;
      tail = fst;
      fst = fst->next;
    } else {
      tail->next = snd;
      tail = snd;
      snd = snd->next;
    }
  }
  while (fst) {
    tail->next = fst;
    tail = fst;
    fst = fst->next;
  }
  while (snd) {
    tail->next = snd;
    tail = snd;
    snd = snd->next;
  }
  tail->next = NULL;
  return rtn->next;
}

在我原来的MacBook上,这会在4秒多的时间内对1000万个随机整数进行排序,这似乎并不太糟糕。

您还可以将追加操作放在宏中,并使其非常简洁:

struct listnode *sort(struct listnode *lst) {
  if (!lst || !lst->next) return lst;
  struct listnode *q = lst, *p = lst->next->next;
  while (p && p->next) {
    q = q->next;
    p = p->next->next;
  }
  struct listnode *mid = q->next;
  q->next = NULL;
  struct listnode *fst = sort(lst), *snd = sort(mid);
  struct listnode rtn[1], *tail = rtn;
  #define APPEND(X) do { tail->next = X; tail = X; X = X->next; } while (0)
  while (fst && snd) if (fst->key < snd->key) APPEND(fst); else APPEND(snd);
  while (fst) APPEND(fst);
  while (snd) APPEND(snd);
  tail->next = NULL;
  return rtn->next;
}