题目地址:https://oj.leetcode.com/problems/sort-list/
题意:简单的说就是不再开辟新的内存,用O(NlogN)的排序将现有链表排序
解题思路:O(NlogN)的复杂度,我想到的是堆排或者归并,但是这道题节点的构造不符合堆排。链表的归并排序我是第一次写,凡是和指针挂钩的都要注意边界处理。
要点:归并排序的要点就是找到中点,然后二分,再合并。
1.拆分:对于链表,找中点就相当于将链表截断为两个长度差小于2的新链表,这里的操作是findMid()函数,注意边界处理。
2.合并:归并排序再合并时将两个有序子链表合并成一个,用链表实现归并排序的好处就是不用像数组实现时开辟新内存空间,这里的操作是merge()函数,要注意链表合并时的极端情况,列如:子列表1的元素全部大于子列表2里的元素。
总结:复习了归并排序,学习了链表的排序。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeSort(ListNode *List){
if(!List||!(List->next)) return List;
ListNode *mid = NULL;
mid = findMid(List);
ListNode* List1 = mergeSort(List);
ListNode* List2 = mergeSort(mid);
return merge(List1,List2);
}
ListNode *findMid(ListNode *head){
ListNode *ptr1=head;
ListNode *ptr2=head->next;
while(ptr2&&ptr2->next){
ptr1 = ptr1->next;
ptr2 = ptr2->next;
if(ptr2->next == NULL) //小心越界
break;
ptr2 = ptr2->next;
}
ListNode *pre = ptr1;
ptr1 = ptr1->next;
pre->next =NULL; //截断两个链表
return ptr1;
}
ListNode* merge(ListNode *List1, ListNode *List2){
ListNode *head = NULL;
ListNode *ptr = NULL;
ListNode *head1 = List1;
ListNode *head2 = List2;
while(head1 != NULL && head2 != NULL){
if(head1->val < head2->val){
if(head == NULL){
ptr = head = head1;
}
else{
ptr->next =head1;
ptr = ptr->next;
}
head1 = head1->next;
}
else{
if(head == NULL){
ptr = head = head2;
}
else{
ptr->next =head2;
ptr = ptr->next;
}
head2 = head2->next;
}
}
while(head1 != NULL){
if(head == NULL)
ptr = head = head1;
else{
ptr->next =head1;
ptr = ptr->next;
}
head1 = head1->next;
}
while(head2 != NULL){
if(head == NULL)
ptr = head = head2;
else{
ptr->next =head2;
ptr = ptr->next;
}
head2 = head2->next;
}
ptr->next = NULL;
return head;
}
ListNode *sortList(ListNode *head) {
return mergeSort(head);
}
};