【问题标题】:C: Merge Sort for linked list, merged subarray not captured correctly in sort functionC:链表的合并排序,排序函数中未正确捕获合并的子数组
【发布时间】:2017-08-07 20:17:48
【问题描述】:

根据 Wikipedia 站点上的合并排序伪代码,我可以深入了解一个节点正确合并到两个节点列表中的基本情况。但是,我认为当它们返回递归链时,合并的部分会反转。

我正在使用 Makefile:

sort: main.c sort.c
    gcc -Wall -std=c99 -o $@ main.c sort.c ll.c

我正在使用包含头指针和尾指针的列表头结构。 Head 指向第一个节点,tail 指向最后一个节点。
合并功能正在工作,但这里是排序功能。

void list_sort(list_t *list)
{
printf("in sort 1\n");

    //base case of 0 or 1 element
    if (list->head == NULL || list->head->next == NULL) {
        return;
    }

    list_t *sublistA = list_create();
    assert(sublistA);
    list_t *sublistB = list_create();
    assert(sublistB);

    int len = Length(list);
    int mid = (len) / 2;
    printf("mid is %d\n", mid);
    int i = 0;
    element_t *current = list->head;
    //make sublists
    while (i < len) {
        if (i < mid) {  
            printf("append sublistA\n");
            list_append(sublistA, current->val);
        } else {
            printf("append sub B\n");
            list_append(sublistB, current->val);
        }
        i++;
        current = current->next;    
    }
    list_print(sublistA);
    list_print(sublistB);

    printf("going to sort A\n");
    list_sort(sublistA);

    printf("going to sort B\n");
    list_sort(sublistB);
    //this was just added to capture returned list from merge
    list_t* capture = NULL;
    assert(capture);//the assertion failed
    capture = merge(sublistA, sublistB);
    }

编辑: 断言失败,所以我切换到:

list_t* capture = list_create();
    assert(capture);

    capture = merge(sublistA, sublistB);

我确信它没有从 main、merge 和 sort 中的 printf 语句中正确捕获。

这是显示意外反转的命令行输出:

/* left and right lists to merge://at the start of the merge function
{ 8, }
{ 7, }
in merge while 1
in merge else 1
{ 7, }
final result
{ 7, 8, }//yay!  this is the last line of merge function
in merge//came right back again to merge
left and right lists to merge:
{ 9, }
{ 8, 7, }//doh!*/

编辑:这里是合并函数:

list_t *merge(list_t *left, list_t *right) {
    printf("in merge\n");
    list_t *result = list_create();
    assert(result);

    element_t *curr1 = left->head;
    element_t *curr2 = right->head;
    //list_t *result = list_create();
    printf("left and right lists to merge: \n");
    list_print(left);
    list_print(right);

    while (curr1 != NULL && curr2 != NULL) {
printf("in merge while 1\n");
        if (curr1->val <= curr2->val) {
            list_append(result, curr1->val);
            printf("merge while 1 if\n");
            curr1 = curr1->next;
            //curr2 = curr2->next;
        }
        else //curr1->val > curr2->val
        {
            printf("in merge else 1\n");
            list_append(result, curr2->val);
            curr2 = curr2->next;
        }
    }
    list_print(result);

    //leftovers need to be allocated
    while (curr1 != NULL) {
        list_append(result, curr1->val);
        curr1 = curr1->next;
    }

    while (curr2 != NULL) {
        list_append(result, curr2->val);
        curr2 = curr2->next;
    }

    //printf("curr1->val is %d\n", curr1->val);
    //printf("curr2->val is %d\n", curr2->val);
    list_destroy(left);
    list_destroy(right);
    printf("final result\n");
    list_print(result);

    return result;
}

【问题讨论】:

  • 当前代码中有很多不可引用的函数。
  • @BLUEPIXY 由于封装而超出范围。输出也已发布。
  • 你能发布你的整个代码吗?至少,您的struct 定义和list_create,尤其是list_append。我相信我在合并中看到了您的问题,但需要查看 list_append 才能确定
  • 链表自顶向下合并排序的wiki伪代码效率非常低。 wiki bottom up merge sort for linked lists 要好得多。如果你真的想对链表进行自上而下的合并排序,我建议在别处寻找(除了 wiki)。

标签: c sorting linked-list mergesort


【解决方案1】:

我注意到您的 merge 函数通过破坏性地修改输入列表来工作:您将两个列表作为输入,生成一个新的合并列表作为输出,然后返回结果列表。但是,在您的 list_sort 函数中,您没有捕获返回的新列表,因此您没有更新提供的输入列表以保存新排序的序列。尝试从merge 捕获返回值并使用它来更新输入列表参数。

【讨论】:

  • 注意到了。我要再试一次。我之前可能拍错了。
  • 我得到了"warning: variable ‘capture’ set but not used [-Wunused-but-set-variable] list_t* capture = NULL;,直到我使用了list_t* capture =list_create()。仍然不起作用,但您的评估是正确的。谢谢。
  • 嗯,你必须对这个变量做一些实际的事情,而不是仅仅声明它。 :-) 想想它包含什么,以及你的函数说它将如何处理它的参数。
  • 此时我最好的猜测是capture 包含指向包含headtail 指针的标头的地址,这些指针初始化为NULL 但随后它被重新分配给返回的@ 987654330@ 来自合并的指针。 printf 语句表明捕获工作正常。但是,我现在是否有该标头的内存泄漏(包含headtail)?此外,当再次调用 merge 时,它​​仍然会反转!
  • @Nobu - merge() 返回一个创建并合并的列表,所以该行应该是list t* capture = merge(...)。 list_sort() 应该返回捕获,并且对 merge 的两个调用应该更改为 sublistA = list_sort(sublistA);sublistB = list_sort(sublistB); 。顺便说一句,这是一种非常低效的方法,意在成为 wiki 文章中自上而下合并排序的一个非常粗略的示例。
猜你喜欢
  • 2023-03-28
  • 2013-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多