原題鏈接:https://leetcode-cn.com/problems/sort-list/
1、歸併排序(遞歸版)
ListNode* sortList(ListNode* head) {
if(head==NULL||head->next==NULL) return head;
ListNode *p=head,*q=head->next;
while(q!=NULL&&q->next!=NULL){//找出鏈表中點
p=p->next;
q=q->next->next;
}
ListNode *mid=p->next;
p->next=NULL;
ListNode *left=sortList(head);//將左右鏈表分別遞歸
ListNode *right=sortList(mid);
ListNode *dummy=new ListNode;
ListNode *t=dummy;
while(left!=NULL&&right!=NULL){//將左右兩邊鏈表排序
if(left->val>right->val){
t->next=right;
right=right->next;
}else{
t->next=left;
left=left->next;
}
t=t->next;
}
t->next=left!=NULL?left:right;
return dummy->next;
}
2、歸併排序(非遞歸版)
模擬歸併排序的分隔部分,初始合併單元長度len=1,每一輪len=len*2,依次合併。
ListNode *sortList(ListNode* head){
ListNode *p=head;
int length=0;
while(p!=NULL){
p=p->next;
length++;
}
ListNode *dummy=new ListNode;//啞頭節點
dummy->next=head;
int len=1;
while(len<length){
ListNode *pre=dummy;//用於合併的輔助頭部
ListNode *h=dummy->next;
while(h!=NULL){
ListNode *h1=h;
int i=len;
while(h!=NULL&&i>0){
h=h->next;
i--;
}
if(i>0) break;//如果鏈表剩餘個數少於len,則無需合併環節,直接break,執行下一輪合併
ListNode *h2=h;
i=len;
while(h!=NULL&&i>0){
h=h->next;
i--;
}
int c1=len;
int c2=len-i;//若h2存在,但以h2爲頭部的剩餘個數少於len,也執行合併環節,h2單元長度爲c2=len-i
while(c1>0&&c2>0){
if(h1->val<h2->val){
pre->next=h1;
h1=h1->next;
c1=c1-1;
}else{
pre->next=h2;
h2=h2->next;
c2=c2-1;
}
pre=pre->next;
}
pre->next=c1>0?h1:h2;
while(c1>0||c2>0){
pre=pre->next;
c1=c1-1;
c2=c2-1;
}
pre->next=h;//合併完後,修改新的合併單元尾部pre指針指向下一個合併單元頭部h
}
len=len*2;
}
return dummy->next;
}