Sort a linked list in O(n log n) time using constant space complexity.
此题要求时间复杂度为O(nlgn)第一印象即用快速排序和归并排序,由于快速排序的不稳定,跨度大,故我决定采用归并排序。网上我记得有看过使用快排的!
#include <iostream.h>
#include <string.h>
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
void printlist(ListNode *head)
{
while(head!=NULL)
{
cout << head->val << " ";
head = head->next;
}
}
void debug_disp(ListNode *head,char *str)
{
cout<<endl<<str;
printlist(head);
}
ListNode *get_midpos(ListNode *head,ListNode *end) {
ListNode *mid_pos,*pre_pos;
ListNode *end_pos;
//if(head == NULL||head->next==NULL)return head;
mid_pos=head;
end_pos=head;
while(end_pos != end&&end_pos->next != end)
{
pre_pos=mid_pos;
mid_pos=mid_pos->next;
end_pos=end_pos->next->next;
}
return pre_pos;
}
ListNode *merge(ListNode *first_lk,ListNode *second_lk) {
ListNode head_temp(0);
ListNode* temp_head = &head_temp;
ListNode *save_head=temp_head;
ListNode* head ;
debug_disp(first_lk,"merge_list1:");
debug_disp(second_lk,"merge_list2:");
while(first_lk!=NULL&&second_lk!=NULL)
{
if(first_lk->val<second_lk->val)
{
temp_head->next=first_lk;
first_lk=first_lk->next;
}
else
{
temp_head->next=second_lk;
second_lk=second_lk->next;
}
temp_head=temp_head->next;
}
if(first_lk != NULL)
temp_head->next=first_lk;
else
temp_head->next=second_lk;
head=save_head->next;
debug_disp(head,"merge:");
return head;
}
ListNode * merge_sort(ListNode *head) {
ListNode *mid_pos,*mid_next_llk;
ListNode *sort_list_1,*sort_list_2;
if(head == NULL||head->next==NULL)return head;//为空或者为单独一个节点
mid_pos=get_midpos(head,NULL);
mid_next_llk=mid_pos->next;//第二个链表位置
mid_pos->next=NULL;//拆分成俩个链表
//debug_disp(head,"list1:");
//debug_disp(mid_next_llk,"list2:");
sort_list_1=merge_sort(head);
sort_list_2=merge_sort(mid_next_llk);
//debug_disp(mid_next_llk,"merge_sort mid_llk:");
return merge(sort_list_1,sort_list_2);//合并
}
ListNode *sortList(ListNode *head) {
return merge_sort(head);
}
int main()
{
ListNode list1(1), list2(2), list3(3), list4(4), list5(5), list6(6);
list1.next = &list3;
list3.next = &list5;
list5.next = &list4;
list4.next = &list2;
list2.next = &list6;
list6.next = NULL;
ListNode *result = sortList(&list1);
debug_disp(&list1,"result:");
return 1;
}
本题小结,个人对着归并排序依葫芦画瓢,结果犯了俩个严重的错误
1、将链表拆成俩部分,需注意取下整,否则产生死循环。并且由于是单链表需提前不能回溯。最后划分后需加上NULL;
2、在归并排序时merge_sort(head);merge_sort(mid_next_llk);merge(sort_list_1,sort_list_2);这样写将会产生错误,
原因为:merge后,对原链表已经修改,但head,mid_next_llk仍指向原地方,并非头结点。此处应该使用其返回值,即首结点。
另外一种改进的方法为:外加一个将链表再加一个头结点,对头结点外的节点节点排序即可,不影响头节点!
注:如有不足请各位给予纠正谢谢!