两个思路:
快速排序(逻辑是自顶向下)。先划分排序(一次确定一个位置),再对左边右边分别排序,一直到最小粒度;
归并排序(逻辑自下而上) 先一直到最小粒度,然后两两合并排序,最合合成排序好的链表;
1,快速排序
1)根据划分位置将链表 分成两部分(左边小于,右边大于),递归:QuickSort(head,end),时间复杂度logn
void QuickSort(ListNode *head ,ListNode *end){
if (head!=end){
ListNode *pivot=Getpartion(head , end);
QuickSort(head,pivot);
QuickSort(pivot->next,end);
}
}
调用 QuickSort(head, NULL) 呼应后面的j!=end,方便处理最后一个节点
2)得到划分的位置:Getpartion(head,end),这里取第一个节点作为默认的划分节点,划分之后,右边全小于该节点,左边全大于该节点,时间复杂度o(n)
pivot x x x x x x x x x x x x
左边 <= pivot <= 右边
ListNode *Getpartion(ListNode *head, ListNode *end){
ListNode *i,*j;
if (head ==Null || end == Null) return;
else{ #思想:i,j。i前面的节点包含该节点 都<= pivot , j与i之间的都是>pivot
int key=head->vaule; i=head; j=head-<next;
while (j!=end){
if (j->vaule<key){
i=i->next; #从第二个节点开始,首节点(这里指的划分节点)不动,最后和i交换
swap(i->vaule,j->vaule);
}
j=j->next;
}
swap(i->vaule,key); #将首节点放在应有的位置上
}
2,归并排序
1)将链表均分成两部分,关键是找到中间节点(两个指针,一个走一步,一个走两步);
ListNode* Merge(ListNode *head){ #这里必须返回节点,因为原来的链表的节点被打乱了重新排序了,区别上面只是交换值,如果这里对两个链表合并排序用交换值得办法,必须牺牲空间o(n),有序链表合并排序不至于这样做
ListNode *i,*j;
i=head;
h-head;
if (head == end) return;
while(j!=end){i=i->next;j=j->next; j=j->next; }
j=i->next;
i->next=Null; #这里使右边节点的最后一个节点指向Null,左边的节点默认指向Null
会方便 后面是两个尾部指向Null的链表合并
ListNode *left=Merge(head);
ListNode *right=Merge(j);
ListNode *sortlist=MergeSort(left,right); #将两条有序的链表合并,返回一条排好序的链表
return sortlist
}
2)两个有序链表的合并排序;
ListNode* MergeSort(ListNode *right ,ListNode *left){
ListNode *i,*j,*a;
i=right;
j=left;
if (i>value>j->value) { a=left ; j=j->next;}
else{a=right;i=i->next; }
while(i!=Null && j!=Null}{
if (i->value>j->value) {a->next=j ; a=a->next ; j=j->next;}
else{ a->next=i ; a=a->next ; i=i->next; }
if (i==Null) while(j!=Null) { a->next=j ; a=a->next ; j=j->next;}
else(j==Null) while(i!=Null) {a->next=i;a=a->next;i=i->next;}
return a;
}