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;
}