【LintCode】Sort List(筆記)

Description

Sort a linked list in O(n log n) time using constant space complexity.

Example

Given 1->3->2->null, sort it to 1->2->3->null.

Notes

主要思想就是如何對鏈表作歸併排序。

1.歸併排序的思想

2.尋找鏈表的中間結點(弄兩個指針,每次循環p1->next,p2->next->next,p2到達終結點時p1就是中間結點)

3.合併兩個已排序鏈表(合併後的鏈表注意要有末尾null,爲了下一次合併)

Solution

/**
 * Definition of ListNode
 * class ListNode {
 * public:
 *     int val;
 *     ListNode *next;
 *     ListNode(int val) {
 *         this->val = val;
 *         this->next = NULL;
 *     }
 * }
 */

class Solution {
public:
    /*
     * @param head: The head of linked list.
     * @return: You should return the head of the sorted linked list, using constant space complexity.
     */
    ListNode * sortList(ListNode * head) {
        // write your code here
        if(head==NULL || head->next==NULL)
            return head;
        return mergeList(head);
    }
    
    ListNode * mergeList(ListNode *head){
        if(head==NULL || head->next==NULL)  //遞歸終點注意
            return head;
        ListNode *lh=head;
        ListNode *rh;
        ListNode *p1=head, *p2=head->next;
        while(p2!=NULL && p2->next!=NULL){
            p1 = p1->next;
            p2 = p2->next->next;
        }
        rh = p1->next;
        p1->next = NULL;
        ListNode *lhalf = mergeList(lh);
        ListNode *rhalf = mergeList(rh);
        return merge(lhalf, rhalf);
    }
    
    ListNode * merge(ListNode *lh, ListNode *rh){
        ListNode *sh;
        if(lh->val<=rh->val){  //解決表頭問題
            sh = lh;
            lh = lh->next;
        }
        else{
            sh = rh;
            rh = rh->next;
        }
        ListNode *p = sh;      //指針p指向表頭
        while(lh&&rh){
            if(lh->val<=rh->val){
                p->next = lh;
                lh = lh->next;
            }
            else{
                p->next = rh;
                rh = rh->next;
            }
            p = p->next;  //鏈表指針要移動
        }
        if(lh!=NULL)      //merge後要有終點,爲了下一次合併
            p->next = lh;
        else
            p->next = rh;
        return sh;
    }
};

這裏的merge函數我原先怎麼都不能AC的錯誤寫法↓

 

    ListNode * merge(ListNode *lh, ListNode *rh){
        ListNode *sh;
        ListNode *p = sh;     //p這裏不能指向sh
        if(lh->val<=rh->val){
            p = lh;
            lh = lh->next;
        }
        else{
            p = rh;
            rh = rh->next;
        }
        while(lh&&rh){
            if(lh->val<=rh->val){
                p->next = lh;
                lh = lh->next;
            }
            else{
                p->next = rh;
                rh = rh->next;
            }
            p = p->next;
        }
        if(lh!=NULL)
            p->next = lh;
        else
            p->next = rh;
        return sh;
    }

如果我一開始讓sh申請內存建個鏈表頭,而不是空指針,就不會有這種錯了。

 

下面的merge函數是正確的寫法↓

 

    ListNode * merge(ListNode *lh, ListNode *rh){
        ListNode *sh = new ListNode(0);
        ListNode *p = sh;        //這樣p指向sh就沒問題了,而且沒有表頭問題
        while(lh&&rh){
            if(lh->val<=rh->val){
                p->next = lh;
                lh = lh->next;
            }
            else{
                p->next = rh;
                rh = rh->next;
            }
            p = p->next;
        }
        if(lh!=NULL) 
            p->next = lh;
        else
            p->next = rh;
        p = sh->next;
        sh->next = NULL;
        delete sh;     //把佔用內存釋放掉
        return p;
    }

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章