[算法]作死的链表排序

链表排序应该最好写的是插入排序,但时间复杂度为O(N),今天遇到了链表的排序问题,记得曾经在leetcode上做了这道题,直接写插入排序会超时,后来只好采用归并排序(不仅时间复杂度为O(NlogN),空间复杂度还是O(1)),然后三下五除二地写了归并排序。以前写的非递归版本,大概是提交了5次调试N久之后通过的吧,今天在纸上一写,发现漏洞百出,后来才发现原来用递归的方式写可以省时省力!哎,当初费力AC了这道题之后应该看看讨论!


1. 链表的插入排序

ListNode *insertionSortList(ListNode *head) {
        if(NULL == head || NULL == head->next)
            return head;
        ListNode *newHead = head;
        ListNode *ptr = head->next;
        newHead->next = NULL;
        while(ptr)
        {
            ListNode *tmp = ptr;
            ptr = ptr->next;
            ListNode *q = newHead;
            if(q->val >= tmp->val)
            {
                tmp->next = q;
                newHead = tmp;
            } else {
                while(q && q->next && q->next->val < tmp->val)
                {
                    q = q->next;
                }
                tmp->next = q->next;
                q->next = tmp;
            }
        }
        return newHead;
    }

2. 链表的归并排序(传说中作死的非递归版本)

ListNode *sortList(ListNode *head) {
        if(!head || !head->next) return head;
        ListNode *ptr = head;
        int n = 0;
        while(ptr)
        {
            ptr = ptr->next;
            ++n;
        }
        for(int i = 1; i < n; i = i * 2)
        {
            ptr = head;
            head = NULL;
            ListNode *tail = NULL;

            while(ptr)
            {
                ListNode *list1 = ptr;
                ListNode *list2 = ptr;
                int l1 = 0;
                while(list2 && l1 < i) // locate list2
                {
                    list2 = list2->next;
                    ++l1;
                }
                ptr = list2;
                int l2 = 0;
                while(ptr && l2 < i) // locate ptr
                {
                    ptr = ptr->next;
                    ++l2;
                }

                int t = 0, s = 0;
                while(t < l1 && s < l2)
                {
                    ListNode *tmp = NULL;
                    if(list1->val <= list2->val)
                    {
                        tmp = list1;
                        list1 = list1->next;
                        ++t;
                    } else {
                        tmp = list2;
                        list2 = list2->next;
                        ++s;
                    }
                    if(tail) tail->next = tmp;
                    tail = tmp;
                    if(!head) head = tail;
                }
                while(t < l1)
                {
                    if(tail) tail->next = list1;
                    tail = list1;
                    list1 = list1->next;
                    if(!head) head = tail;
                    ++t;
                }
                while(s < l2)
                {
                    if(tail) tail->next = list2;
                    tail = list2;
                    list2 = list2->next;
                    if(!head) head = tail;
                    ++s;
                }
            }
            if(tail) tail->next = NULL;
        }
        return head;
    }

3. 链表归并排序的递归版本

ListNode * sortList(ListNode *head)
{
    if(NULL == head || NULL == head->next)
        return head;
    ListNode *slow = head;
    ListNode *fast = head->next;
    while(fast && fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;
    }
    fast = slow->next;
    slow->next = NULL;
    slow = head;
    slow = sortList(slow);
    fast = sortList(fast);
    ListNode *h = NULL;
    ListNode *last = NULL;
    while(slow && fast)
    {
        if(slow->val <= fast->val)
        {
            if(last) last->next = slow;
            else h = slow;
            last = slow;
            slow = slow->next;
        } else {
            if(last) last->next = fast;
            else h = fast;
            last = fast;
            fast = fast->next;
        }
    }
    last->next = NULL;
    if(slow) last->next = slow;
    if(fast) last->next = fast;
    return h;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值