148. 排序链表

题目

链表:排序链表
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

示例 1:
在这里插入图片描述

输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:
在这里插入图片描述

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:
输入:head = []
输出:[]

提示:

链表中节点的数目在范围 [0, 5 * 104] 内
-105 <= Node.val <= 105

进阶:你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(!head||!head->next)//若该链表为空或者只有一个节点直接返回头结点
        {
            return head;
        }
        ListNode* slow=head;//通过快慢指针的方法找到中间节点
        ListNode* fast=head->next;
        while(fast&&fast->next)//通过循环可以找到中间节点,此时该节点就是拆分后第一个链表的最后一个节点
        {
            slow=slow->next;
            fast=fast->next->next;
        }
        ListNode* second=slow->next;//第二个链表
        slow->next=NULL;//将两个链表分开
        ListNode* first=head;//第一个链表
        first=sortList(first);//通过递归的方式继续将链表一分位2
        second=sortList(second);
        return mergeList(first,second);//然后将链表合并,并且返回合并后的链表
        
    }
    ListNode* mergeList(ListNode* left,ListNode* right)
    {
        ListNode* dummy=new ListNode(0);//虚拟节点可以避免处理一些边界条件
        ListNode* tail=dummy;//尾节点
        while(left&&right)
        {
            if(left->val<right->val)
            {
                tail->next=left;
                left=left->next;
            }else
            {
                tail->next=right;
                right=right->next;
            }
            tail=tail->next;//尾节点始终指向链表的最后一个节点
        }
        if(left)//最后若left不为空,直接连接到尾节点后面,否则连接right
        {
            tail->next=left;
        }else{
            tail->next=right;
        }
        return dummy->next;
    }
};

原理图

基于链表的特性适合归并排序,时间复杂度O(nlogn),空间复杂度O(1)
假设链表中有n个节点,每次拆分是logn合并也是logn,每个节点都参与了,所以总起来是nlogn。
在这里插入图片描述

原理解释

提示:算法流程及解释在代码中已标注
总体步骤需要分为两部分,一部分是将链表通过递归一分为2,第二部分是通过比较大小合并链表

如上原理图流程:
①将4、2、1、3划分为4、2和1、3
②然后将4、2划分为4和2,将1、3划分为1和3,相当于四个链表
③接下来是合并操作,将4、2这两个链表通过比较合并为2、4,1、3这两个链表通过比较合并为2、4
④然后再将合并后的两个链表比较,1比2小,1后边连接2,然后是3相对较小,最后把4连在后边。

小结

排序链表的归并排序算法是一种高效的排序方法,它基于分治思想,将链表逐步拆分成更小的子问题,然后合并这些问题的解决方案以得到最终排序结果。这样的归并排序算法在时间复杂度上为 O(nlogn),空间复杂度为 O(1)。
在这里插入图片描述
原理图借鉴哔站华南溜达虎,如有侵权联系删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小辉同志

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值