148. 排序链表(归并排序)

 题目描述:

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

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

示例 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

 解题思路:

利用快慢指针,找到中间结点,因为fast比slow多走一倍的长度,因此当fast结束时,slow指向中间结点,将链表按照slow分成左右两边,调用mergeSort函数,继续对子链表进行分割,最终指向合并排序操作。

排序链表(优先队列 / 归并排序(再看)☀) - 排序链表 - 力扣(LeetCode) (leetcode-cn.com)

利用归并的思想,递归地将当前链表分为两段,然后 merge。

分两段的方法是使用快慢指针,fast 一次走两步,slow 一次走一步。因为 fast 指针走的遍历的节点数是 slow 指针遍节点数的两倍,所以当 fast 指针遍历到链表末尾时,此时 slow 指针所在位置就是链表的中间位置,这样就将当前链表分成了两段。

merge 时,把两段头部节点值比较,定义一个 p 指针指向较小的节点,且记录第一个节点,然后两段链表从头一步一步向后走,p 也一直向后走,总是指向较小节点,直至其中一个头为 NULL,继续处理剩下的元素,最后返回记录的头即可。

代码实现:

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        
        if (head == NULL) return NULL;//头结点为空,返回null
        return mergeSort(head);
    }

    ListNode *mergeSort(ListNode *head) {

        if (head == NULL || head->next == NULL) return head;

        //利用快慢指针来找到链表的中点
        ListNode *fast = head;
        ListNode *slow = head;
        //当满足快指针不为空,并且next指针不为空,next next指针不为空,为了保证修改指针过程中没有越界
        while (fast != NULL && fast->next != NULL && fast->next->next != NULL) {

            fast = fast->next->next;//快指针走两步
            slow = slow->next;//慢指针走一步
        }
        //块是慢的两倍,所以当块在最后的时候,慢在中间,执行中间结点
        ListNode *right = mergeSort(slow->next);// 接下来开始进行分链表,递归分
        slow->next = NULL;//不要忘记将慢指针的next指针置为null
        ListNode *left = mergeSort(head);//分slow左边的链表,递归分。
        
        return merge(left, right);//最后将已经处理好的左右两边进行归并。
    }

    ListNode *merge(ListNode *left, ListNode *right) {//归并排序的处理,传入的参数是两个已经拍好顺序的两个链表的头指针。

        ListNode *dummyHead = new ListNode(0);//创建头指针,new一个新的元素
        ListNode *p = dummyHead;//p指针初始化为头指针,p的作用是指向较小的结点

        while (left != NULL && right != NULL) {//两个链表都不为空的时候,进入循环

            if (left->val <= right->val) {//从各自的头结点进行比较,当满足left的val小于等于right的val时

                p->next = left;//将left指向结点连接到p的后面
                left = left->next;//更新left指针,向后移动一个位置
            } else {
                p->next = right;//否则将right指向的结点,连接到p后面,将right后移一个元素
                right = right->next;
            }
            p = p->next;//更新p,将p指向新创建的链表的最后一个元素。
        }
        //其中一个链表为空,直接将剩余的元素直接连接到p的后面。
        if (left != NULL) p->next = left;
        if (right != NULL) p->next = right;

        return dummyHead->next;//最终饭后头结点。
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值