链表排序

问题:排序链表

要求:对链表进行排序,要求 时间复杂度O(n logn) 空间复杂度常数级别

PS: 学习链表寻找中点的方法

解法一:归并排序的递归解法(空间复杂度不符合,递归栈使用空间)

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)
    {
        return  (head == nullptr) ? nullptr : mergeSort(head);
    }

private:
    ListNode * findMid(ListNode * head)
    {
        ListNode * slow = head;
        ListNode * fast = head;
        while (fast->next != nullptr && fast->next->next != nullptr)
        {
            slow = slow->next;
            fast = fast->next->next;
        }
        // split the list into two parts
        ListNode * newHead = slow->next;
        slow->next = nullptr;
        return newHead;
    }

    ListNode * mergeTwoLists(ListNode * l1, ListNode * l2)
    {
        if (l1 == nullptr) return l2;
        if (l2 == nullptr) return l1;

        if (l1->val < l2->val) {
            l1->next = mergeTwoLists(l1->next, l2);
            return l1;
        }
        else {
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }

    ListNode * mergeSort(ListNode * head)
    {
        if (head->next == nullptr) return head;
        ListNode * mid = findMid(head);
        ListNode * l1 = mergeSort(head);
        ListNode * l2 = mergeSort(mid);
        return mergeTwoLists(l1, l2);
    }
};

 

解法二:快排的迭代解法(空间复杂度不符合,递归栈使用空间)

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:
    
    void quickSortList(ListNode* pre, ListNode* head, ListNode* tail)
    {
        if (head != tail && head->next != tail)
        {
            ListNode * mid = partition(pre, head, tail);
            quickSortList(pre, pre->next, mid);
            quickSortList(mid, mid->next, tail);
        }
    }

    ListNode * partition(ListNode* pre, ListNode* start, ListNode* end)
    {
        int key = start->val;
        ListNode * head1 = new ListNode(-1);
        ListNode * head2 = new ListNode(-1);
        ListNode * s = head1;
        ListNode * e = head2;

        for (ListNode *node = start->next; node != end; node = node->next)
        {
            if (node->val <= key)
            {
                s->next = node;
                s = node;
            }
            else
            {
                e->next = node;
                e = node;
            }
        }
        e->next = end;
        s->next = start;
        start->next = head2->next;
        pre->next = head1->next;
        return start;
    }

    ListNode* sortList(ListNode* head) {
        if (head == nullptr || head->next == nullptr)
        {
            return head;
        }

        ListNode * pre = new ListNode(0);
        quickSortList(pre, head, nullptr);
        return pre->next;
    }
};

 

解法三:归并排序的迭代解法

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:
    //cut n个节点,然后返回剩下的链表的头节点
    ListNode * cut(ListNode * head, int n)
    {
        ListNode * p = head;
        while (--n && p)
        {
            p = p->next;
        }
        if (p == nullptr)
        {
            return nullptr;
        }

        ListNode *subc = p->next;
        p->next = nullptr;
        return subc;
    }

    //迭代合并链表
    ListNode * merge(ListNode* l1, ListNode* l2)
    {
        ListNode * pre = new ListNode(0);
        ListNode * p = pre;

        while (l1 && l2)
        {
            if (l1->val < l2->val)
            {
                p->next = l1;
                l1 = l1->next;
            }
            else
            {
                p->next = l2;
                l2 = l2->next;
            }
            p = p->next;
        }
        p->next = l1 ? l1 : l2;
        return pre->next;
    }

    ListNode* sortList(ListNode* head) {
        if (head == nullptr || head->next == nullptr)
        {
            return head;
        }

        //先求得链表的长度,然后根据长度来cut
        int length = 0;
        ListNode * p = head;
        while (p)
        {
            length++;
            p = p->next;
        }

        //第一次cut 1,然后根据归并的思路,cut的大小依次*2,边界条件为size<length,因为size==n表示的是链表的每个长度为n的段已经是有序的了,执行循环的目的就是把有序的长度为n的段连起来,因此当size>=length时,表示长度为size的段已经有序,即原链表已经归并完成,结束循环。只有当size<length时才表明没有归并完成,进入循环继续归并
        ListNode * pre = new ListNode(0);
        pre->next = head;
        for (int size = 1; size< length; size *= 2)
        {
            //cur表示待分割链表的第一个节点,tail表示已经合并好的链表的最后一个节点
            ListNode * cur = pre->next;
            ListNode * tail = pre;

            while (cur)
            {
                ListNode * left = cur;
                ListNode * right = cut(left, size);
                cur = cut(right, size);
                tail->next = merge(left, right);
                while (tail->next)
                    tail = tail->next;
            }
        }
        return pre->next;
    }
};

 

posted @ 2020-10-19 18:38  r1-12king  阅读(135)  评论(0编辑  收藏  举报