力扣-148-排序链表

传送门

题目分析:题目要求时间复杂度为$O(nlogn)$,空间复杂度为$O(1)$,根据时间复杂度,我们自然能想到二分,故这里要用到归并排序。对链表的排序,可以通过修改指针来更改节点顺序,无需像数组一样额外开辟存储空间。归并排序有递归和非递归的做法,这里采用递归的做法。

首先,讲一下什么是归并排序?

归并排序采用了分治法的思想,对于一个很大的数列的排序,将其对等分为左右两个子数列进行排序,按照递归的思想继续对等划分,直至数列中只有一个元素(一个元素就不用排序了)。然后再一层一层地合并(注意这里合并是按照小的再前进行的)。

具体的做法如下:

  • 分割$cut$环节: 找到当前链表中点,并从中点将链表断开(以便在下次递归$cut$时,链表片段拥有正确边界);
    我们使用$fast$和$slow$快慢双指针法,奇数个节点找到中点,偶数个节点找到中心左边的节点。
    找到中点$slow$后,执行$slow->next = NULL$将链表切断。
    递归分割时,输入当前链表左端点$head$和中心节点$slow$的下一个节点$temp$(因为链表是从$slow$切断的)。
    $cut$递归终止条件: 当$head.next == NULL$时,说明只有一个节点了,直接返回此节点。

  • 合并$merge$环节: 将两个排序链表合并,转化为一个排序链表。
    双指针法合并,建立辅助$ListNode* h $作为头部。
    设置两指针$ left$, $right$ 分别指向两链表头部,比较两指针处节点值大小,由小到大加入合并链表头部,指针交替前进,直至添加完两个链表。
    返回辅助$ListNode* h$作为头部的下个节点 $h->next$。
    时间复杂度$O(l + r)$,$l$, $r$ 分别代表两个链表长度。

  • 注意:如果$head==NULL$或者$head->next==NULL$时直接返回$head$即可。
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if (head == NULL || head->next == NULL)
            return head;
        
        //寻找链表的中点:链表有奇数个节点,slow返回List的中点;链表有偶数个节点,slow返回List中心的左侧
        ListNode* fast = head->next;
        ListNode* slow = head;
        while(fast != NULL && fast->next != NULL) {
            slow = slow->next;
            fast = fast->next->next;//快指针指到链表末尾时,慢指针刚好指到链表中间
        }
        ListNode* temp = slow->next;
        slow->next = NULL;
        
        //将左链表和右链表分别排序
        ListNode* left = sortList(head);
        ListNode* right = sortList(temp);
        
        ListNode* h = new ListNode(0);
        ListNode* result = h;
        
        //合并
        while(left != NULL && right != NULL) {
            if (left->val < right->val) {
                h->next = left; 
                left = left->next;
            } else {
                h->next = right;
                right = right->next;
            }
            h = h->next;
        }
        h->next = left == NULL? right:left;
        return result->next;
    }
};

 

posted @ 2020-08-08 11:29  Peterxiazhen  阅读(242)  评论(0编辑  收藏  举报