使用链表合并排序 C 实现

Posted

技术标签:

【中文标题】使用链表合并排序 C 实现【英文标题】:Merge Sort C implementation with linked lists 【发布时间】:2022-01-03 02:45:52 【问题描述】:

在尝试将排序与 C 中的链表合并时,我遇到了一个分段错误核心转储。似乎无法跟踪问题的根本原因:

这是我的节点结构:

typedef struct node0* node;
struct node0
    int val;
    node next;
node0;

这是我的分割函数:

node* divide(node head)
    float mid = ceilf((float)length(head)/2);
    node* ret = malloc(sizeof(node)*2);
    node tmp1 = head;
    while (mid>1)
        tmp1 = tmp1->next;
        mid--;
    
    node tmp2 = tmp1->next;
    tmp1->next = NULL;
    ret[0] = head;
    ret[1]=tmp2;
    return ret;

这是我的合并函数:

node mergesorted(node head1, node head2)
    node ret = NULL;
    if(head1 == NULL) return head2;
    else if(head2 == NULL) return head1;
    if(head1->val <= head2->val)
        ret = head1;
        ret->next = mergesorted(head1->next, head2);
     else 
        ret = head2;
        ret->next = mergesorted(head1, head2->next);
    
    return ret;

这是常规的归并排序算法:

node merged(node head)
    if(length(head)>1)
        node *lists = divide(head);
        merged(lists[0]);
        merged(lists[1]);
        return mergesorted(lists[0], lists[1]);

    

主要:

int main() 
    node l1 = create_node(1);
    l1->next = create_node(3);
    l1->next->next = create_node(4);
    l1->next->next->next= create_node(2);
    l1 = merged(l1);
    print_list(l1);

添加一些打印后,我得到以下日志:

deviding: 1-->3-->4-->2-->
devided into:
l1: 1-->3-->
l2: 4-->2-->

deviding: 1-->3-->
devided into:
l1: 1-->
l2: 3-->

merging: 1-->
with: 3-->
merged:1-->3-->

deviding: 4-->2-->
devided into:
l1: 4-->
l2: 2-->

merging: 4-->
with: 2-->
merged:2-->4-->

merging: 1-->3-->
with: 4-->
merged:1-->3-->4-->

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

在最终合并时,右侧列表指针似乎为空!

【问题讨论】:

【参考方案1】:

由于以下片段而出现问题:

    if(head1->val <= head2->val)
        ret = head1;
        ret->next = mergesorted(head1->next, head2);
     else 
        ret = head2;
        ret->next = mergesorted(head1, head2->next);
    

如果您看到,每次值变小或变大时,您都会分配一个新的“头”!这不应该是明确的意图。

只有当结果节点为emptyNULL 时,您才需要创建/附加一个新头。

    if(head1->val <= head2->val)
        if(ret == NULL)
          ret = head1;
        
        ret->next = mergesorted(head1->next, head2);
     else 
        if(ret == NULL)
          ret = head2;
        
        ret->next = mergesorted(head1, head2->next);
    

我在您的代码中没有发现任何其他问题。

【讨论】:

以上是关于使用链表合并排序 C 实现的主要内容,如果未能解决你的问题,请参考以下文章

剑指Offer-16.合并两个排序的链表(C++/Java)

代码模板实现双向链表的去重拼接合并排序

合并两个排序的链表

LeetCode JavaScript实现 合并链表 题型汇总

C++中STL中list的merge函数实现两个无序链表合并,合并后的链表是怎么排序的?例如合并1

c_cpp 合并两个排序的链表的.cpp