Wednesday, November 4, 2015

Sort a linked list in O(n log n) time O(1) space

Sort a linked list in O(n log n) time using constant space complexity.
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

Solution: This is a standard mergesort , but only in linklist way. Merge Sort is O(nlgn) and the sort needs to be done in place so it is O(1) space
Be careful:
1) when we divide the link lists to two parts, do not forget to point the last left next to nullptr;
2) in merge, for efficiecy, always move the pointer as far as possible, denote local start and end, insert the whole local piece to the other;  Then continue with next comparison.
3)The merge code is too long. Need look for a shorter code and easier logic. 
:::Just wrote a recursive version. It is easier logic, but if there are many continuous elements, it wasted some link broken and re-connect.

    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if (!l1) return l2;
        if (!l2) return l1;
        //l1 and l2 have nodes
        ListNode*ret ;
        if (l1->val<l2->val){
            ret=l1;
            ListNode*l1next= mergeTwoLists(l1->next, l2);
            l1->next=l1next;            
        }else{
            ret=l2;
            ListNode*l2next= mergeTwoLists(l1, l2->next);
            l2->next=l2next;
        } 
        return ret;

    }
////////////////////__________________________________________________________
//change   with more  moving forward
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if (!l1) return l2;          if (!l2) return l1;
        //l1 and l2 have nodes
        ListNode*ret ;
        if (l1->val<l2->val){
            ret=l1;
            while (l1->next && l1->next->val<l2->val){
                   l1=l1->next;
            }
            ListNode*l1next= mergeTwoLists(l1->next, l2);
            l1->next=l1next;            
        }else{
            ret=l2;
             while (l2->next && l2->next->val<=l1->val){
                   l2=l2->next;
            }  
           ListNode*l2next= mergeTwoLists(l1, l2->next);
            l2->next=l2next;
        } 
        return ret;

    }
///////////////////__________________________________________________________ class LnikListSort{
public:
 ListNode* sortL(ListNode* head, int N){
        //end condition
        if (N<2) return head;
        if (head==nullptr) return head;
        if (N==2){
            if (head->val<head->next->val) return head;
            ListNode* next= head->next;
            head->next->next= head;
            head->next=nullptr;
            return next;
        }
        //get the middle Node
        ListNode* mid=head;
        for (int i=0; i<N/2; ++i){
            mid= mid->next;
        }
        ListNode* midNext=mid->next;
        mid->next=nullptr;
        int left= N/2+1;  //count mid in left
        int right=N-N/2-1; 
        ListNode* headL=sortL(head, left);
        ListNode* headR=sortL(midNext, right);
        return mergeL(headL, left, headR, right);
    }
    
    ListNode* mergeL(ListNode* headL, int left, ListNode* headR, int right){
        if (left==0) return headR;
        if (right==0) return headL;
        ListNode *curL=headL, *curR=headR, *ret;
        if (headL->val<headR->val) ret=headL;
        else ret= headR;
        int l=0, r=0;
        //2 3  //4
        while (l<left && r<right ){
            
            if (curL->val< curR->val) {
                while(l+1<left && curL->next->val<=curR->val){
                    curL=curL->next;
                    l++;
                }
                if (l+1<left ){ //l has next
                    ListNode* frontR=curR;
                    while (r+1<right && curL->next->val>= frontR->next->val){
                        frontR=frontR->next;
                        r++;
                    }
                    ListNode* rHeadNew=frontR->next; r++;
                    { //insert in curR~frontR cur right node, l++
                        ListNode* lNext= curL->next;
                        curL->next=curR;
                        frontR->next=lNext;
                        curL=lNext;  //l=l;
                        l++;
                        curR=rHeadNew;
                    }
                }else{  //l is done; we link current r, done
                    curL->next=curR;
                    break;
                }
            }else{
                while(r+1<right && curR->next->val<=curL->val){
                    curR=curR->next;
                    r++;
                }
                if (r+1<right ){ //r has next
                    ListNode* frontL=curL;
                    while (l+1<left && curR->next->val>= frontL->next->val){
                        frontL=frontL->next;
                        l++;
                    }
                    ListNode* lHeadNew=frontL->next; l++;
                    { //insert in curR~frontR cur right node, l++
                        ListNode* rNext= curR->next;
                        curR->next=curL;
                        frontL->next=rNext;
                        curR=rNext;  //l=l;
                        r++;
                        curL=lHeadNew;
                    }
                }else{  //l is done; we link current r, done
                    curR->next=curL;
                    break;
                }
            }
        }
        return ret;
    }    
    ListNode* sortList(ListNode* head) {
        //count the length of the list
        ListNode* cur=head;
        int N=0;
        while (cur){
            N++;
            cur=cur->next;
        }
        return sortL(head, N);
    }
};



No comments:

Post a Comment