sort-list(链表的归并排序)

  • 问题描述
    Sort a linked list in O(n log n) time using constant space complexity.
    对一个链表进行排序,且时间复杂度要求为 O(n log n) ,空间复杂度为常量。

  • 问题分析&解题思路
    要求时间复杂度为O(n log n),想到了归并排序。
    利用归并的思想,递归地将当前链表分为两段,然后merge。
    ①找到链表中间节点(位置上的中间),从该节点处分成左右两部分;
    ②左右节点分别递归第①步;
    ③合并左右两个链表。

  • 代码实现

/**
 * 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(NULL == head || NULL == head->next)
            return head;

        ListNode *mid = findMiddle(head);
        ListNode *right = sortList(mid->next);
        mid->next = NULL;
        ListNode *left = sortList(head);

        return mergeList(left, right);
    }

    //快慢指针找中间节点
    ListNode *findMiddle(ListNode *head){
        ListNode *fast = head->next;
        //一定要是head->next,否则偶数个节点时,两段节点不均分
        ListNode *slow = head;
        while(fast != NULL && fast->next != NULL)
        {
            fast = fast->next->next;
            slow = slow->next;
        }
        return slow;
    }

    //合并两个链表
    ListNode *mergeList(ListNode *left, ListNode *right){
        if(NULL == left)
            return right;
        if(NULL == right)
            return left;

        ListNode *ret = new ListNode(0);
        ListNode *head = ret;
        //head指向两者较小的一个,记录其第一个节点
        //两链表头继续向后走,head也向后走,且总是指向较小的
        //直至其中一个为NULL,处理剩下的节点
        //返回记录的头,ret->next
        while(left != NULL && right != NULL)
        {
            if(left->val > right->val)
            {
                head->next = right;
                right = right->next;
            }
            else
            {
                head->next = left;
                left = left->next;
            }
            head = head->next;
        }
        if(NULL == left)
            head->next = right;
        if(NULL == right)
            head->next = left;

        return ret->next;
    }
};
  • 特别强调
    代码中快指针必须声明为head->next。
    此时,从慢指针处一分为二。head到slow是2个节点,slow->next到NULL也是2个节点。
    快指针为head->next
    如果声明快指针声明为head。
    此时,head到slow是3个节点,slow->next是一个节点。
    快指针为head
    节点个数为奇数个时,必然一个比另一个多一个节点。

猜你喜欢

转载自blog.csdn.net/Ananbei/article/details/80692211