归并排序的链表实现

本文介绍了一种链表排序方法——归并排序,并详细展示了其实现过程。通过找到链表中值,将链表分为两部分,再递归地对两部分进行排序,最后合并两个已排序的部分得到完整有序链表。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

利用归并法可以对链表进行排序,而且不需要占用额外空间.对于一个无序链表,先利用循环找到链表的中值,再利用递归先将一个链表分成两个链表,逐步递归,递归停止的条件是链表中只有一个元素或是没有元素的情况,然后完成链表的有序.

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <stack>
#include <queue>
#include <malloc.h>
using namespace std;
#define OK 1
#define ERROR -1
#define TRUE 1
#define FALSE 0
typedef int Status;
typedef struct node *link;
struct node{
    int data;//值域
    link next;//指针域
};
//输出链表的函数
void Print(link head)
{
    while(head != NULL)
    {
        printf("%d ", head->data);
        head = head->next;
    }
    printf("\n");
}
//合并链表的函数
link Merge(link a, link b)
{
    link head = (link)malloc(sizeof(struct node));
    link c = head;
    //如果链表a,b均不为空时,
    while((a != NULL) && (b != NULL))
    {
        //比较大小,将小的一个连入c中
        if(a->data < b->data)
        {
            c->next = a, c = a, a = a->next;
        }
        else
        {
            c->next = b, c = b, b = b->next;
        }
    }
    //当其中一个链表为空时,将另一个不为空的链表整体连入c中
    c->next = (a == NULL) ? b : a;
    //将链表c的头结点返回
    return head->next;
}
//归并排序函数
link mergeSort(link c)
{
    link a = c, b = c->next;
    //当链表为空,或链表中只有一个元素时,递归停止
    if(a == NULL || b == NULL)
    {
        return c;
    }
    //  循环: 为了找到待归并链表的中值位置
    while((b != NULL) && (b->next != NULL))
    {
        c = c->next;
        b = b->next->next;
    }
    // 将b 指向中间位置.
    b = c->next;
    //将链表断为两部分
    c->next = NULL;
    //对链表的两部分进行归并
    Merge(mergeSort(a), mergeSort(b));
}

int main()
{
    //为链表的归并排序举一个例子
    int i, n = 12;
    link p, head;
    //尾插法
    for(i = 0; i < n; i++)
    {
        int num;
        scanf("%d", &num);
        if(i == 0)//该情况为输入链表的第一个元素
        {
            p = (link)malloc(sizeof(struct node));
            head = p;
            p->data = num;
            p->next = NULL;
        }
        else//插入链表中除第一个元素的情况
        {
            link q = (link)malloc(sizeof(struct node));
            q->data = num;
            p->next = q;
            q->next = NULL;
            p = q;
        }
    }
    //将头节点返回
    head =  mergeSort(head);
    //输出函数
    Print(head);
}

 

<think>好的,用户想了解如何用归并排序链表进行排序的实现方法。首先,我需要回忆一下归并排序的基本原理。归并排序是分治法的典型应用,分为分割和合并两个阶段。对于数组来说,分割需要找到中点,但链表无法随机访问,所以必须用快慢指针法来找中点。这一点我记得没错,引用[1]提到链表更适合归并排序,因为其他算法如快速排序在链表上性能不佳,所以用户的问题应该围绕如何分割链表并合并。 接下来,合并两个已排序链表的步骤。这部分应该和数组类似,但链表需要调整指针而不是创建新数组。需要确保合并后的链表正确连接每个节点。引用[4]提到能否在O(1)空间内实现,所以可能要考虑自底向上的方法,避免递归调用带来的栈空间,但用户的问题可能更关注基本实现,先处理递归方法。 然后,具体的实现步骤。分割链表时,快慢指针找到中间节点,然后断开链表为前后两部分。合并时,使用哑节点来简化头节点的处理。需要处理剩余节点,比如当一边链表还有元素时,直接接在合并链表的后面。这部分需要注意指针操作的正确性,避免循环引用或者断链。 代码部分,用户可能需要Python的实现。但Python的链表操作通常用类表示节点,所以需要先定义节点结构。然后实现找到中间节点的函数,分割链表,合并函数,以及递归调用的归并排序主函数。需要检查递归终止条件,比如链表为空或只有一个节点时直接返回。 验证正确性方面,考虑不同长度的链表,比如奇数个节点和偶数个节点的情况,确保分割正确。合并过程中,测试两个链表的不同排列,比如一个全小于另一个,或者交替大小的情况。还要注意处理链表的末尾节点的next指针设为None,避免出现环。 引用中提到的问题,比如空间复杂度。递归的归并排序由于递归调用栈,空间复杂度是O(log n),而自底向上的方法可以达到O(1)空间。但用户的问题可能只需要基本实现,所以先提供递归版本,再在相关问题中提到优化方法,比如引用[4]的问题。 最后,确保回答符合用户的要求,包括分步骤解释、代码示例和相关问题。同时引用相关文献,比如引用[1]指出归并排序更适合链表,引用[4]提到时间复杂度和空间的要求。确保所有数学公式用$...$格式,如时间复杂度O(n log n)。</think>### 归并排序实现链表的排序方法 归并排序链表的理想排序算法,因为它天然适应链表的顺序访问特性,避免了随机访问带来的性能损失[^1]。以下是分步实现方法: --- #### 步骤1:定义链表节点结构 ```python class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next ``` --- #### 步骤2:分割链表(分治法的核心) 使用**快慢指针法**找到中点并断开链表: ```python def split(head): if not head or not head.next: return head, None # 快指针每次走两步,慢指针每次走一步 slow, fast = head, head.next while fast and fast.next: slow = slow.next fast = fast.next.next # 断开链表为前后两半 mid = slow.next slow.next = None return head, mid # 返回前半段和后半段的头节点 ``` --- #### 步骤3:合并两个有序链表 ```python def merge(l1, l2): dummy = ListNode(-1) # 哑节点简化边界处理 curr = dummy while l1 and l2: if l1.val <= l2.val: curr.next = l1 l1 = l1.next else: curr.next = l2 l2 = l2.next curr = curr.next # 处理剩余节点 curr.next = l1 if l1 else l2 return dummy.next ``` --- #### 步骤4:递归完成归并排序 ```python def merge_sort(head): if not head or not head.next: # 递归终止条件 return head # 分割链表 left, right = split(head) # 递归排序子链表 left_sorted = merge_sort(left) right_sorted = merge_sort(right) # 合并排序后的子链表 return merge(left_sorted, right_sorted) ``` --- ### 算法特性 1. **时间复杂度**:$O(n \log n)$,分割和合并各需要$\log n$层操作 2. **空间复杂度**:递归栈空间$O(\log n)$,合并过程仅修改指针无需额外空间[^4] 3. **稳定性**:当元素相等时保持原有顺序 --- ### 关键点解析 1. **快慢指针分割**:避免链表随机访问的劣势,时间复杂度$O(n)$ 2. **哑节点技巧**:简化链表头节点处理的边界条件 3. **原地修改指针**:合并时直接调整节点指针,空间复杂度优于数组归并排序[^1] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值