题目描述:Sort a linked list in O(n log n) time using constant space complexity.
问题分析
时间复杂度为O(nlogn)的排序算法一般有快速排序和归并排序两种。通常情况下快速排序适用于数组,基于链表的快速排序要重新设计指针扫描方案。而自底向上的归并排序本身比较适合与链表。
快速排序
参考http://blog.csdn.net/otuhacker/article/details/10366563的方法,博主给出的是cpp,此处附上Java代码
public class QuickSort
{
public static ListNode sortList(ListNode head)
{
sortList(head,null);
return head;
}
private static void sortList(ListNode h,ListNode e)
{
if(h==e) return;
ListNode mid=partition(h,e);
sortList(h,mid);
sortList(mid.next,e);
}
private static ListNode partition(ListNode h,ListNode e)//切分
{
int k=h.val;
ListNode i=h,j=h.next;
while(j!=e)
{
if(j.val<k)
{
i=i.next;
exch(i,j);
}
j=j.next;
}
exch(h,i);
return i;
}
private static void exch(ListNode i,ListNode j)
{
int temp=j.val;
j.val=i.val;
i.val=temp;
}
}
归并排序
自底向上的归并排序只需要重新组织链表链接就能将链表原地排序
java版本1
public class MergeSort { // 归并排序
public static ListNode sortList(ListNode head)//自底而上
{
int N=0;
for(ListNode k=head;k!=null;k=k.next) N++;
ListNode p=new ListNode(0);
p.next=head;
ListNode h=p;
for(int sz=1;sz<N;sz=sz+sz)
{
p=h;
while(p.next!=null)
{
p =merge(p, sz);
}
}
return h.next;
}
private static ListNode merge(ListNode p,int sz)
{
int c=0;
ListNode i=p,j=p;
for(int k=0;k<sz&&j.next!=null;k++)
j=j.next;
ListNode m=j;
while(true)
{
if(c>=sz||j.next==null) break;
if(i==m){j=j.next;c++;continue;}
if(i.next.val<=j.next.val)
i=i.next;
else
{
insert(i, j);
c++;
}
}
return j;
}
private static void insert(ListNode i,ListNode j)
{
ListNode k=j.next;
j.next=j.next.next;
k.next=i.next;
i.next=k;
i=k.next;
}
}
leetcode 自上而下代码
public class Solution {
public ListNode sortList(ListNode head) {
if (head == null || head.next == null)
return head;
ListNode slow = head;
ListNode fast = head.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode right = sortList(slow.next);
slow.next = null;
ListNode left = sortList(head);
// /待左右两边各自有序,进行归并即可
ListNode temp_head = new ListNode(0);
ListNode temp_node = temp_head;
while (left != null && right != null) {
if (left.val < right.val) {
temp_node.next = left;
left = left.next;
} else {
temp_node.next = right;
right = right.next;
}
temp_node = temp_node.next;
}
if (left != null)
temp_node.next = left;
if (right != null)
temp_node.next = right;
return temp_head.next;
}
}