本题目来源于LeetCode,具体如下:
Sort a linked list in O(n log n) time using constant space complexity.
题目要求复杂度O(nlogn),因此我们很自然考虑使用快速排序或者归并排序,但是后来经过实践证明,使用快速排序总是AC超时,归并排序则可以正确AC。
分析一下原因,个人认为是与测试数据有关,因为快速排序不能保证算法复杂度一定是O(nlogn),当数据比较集中时,即使做随机选取key值,算法的复杂度也非常接近O(N^2),因此会出现超时,所以考虑使用归并排序。
下面是采用归并排序的思路已经AC代码:
主要考察3个知识点,
知识点1:归并排序的整体思想
知识点2:找到一个链表的中间节点的方法
知识点3:合并两个已排好序的链表为一个新的有序链表
归并排序的基本思想是:找到链表的middle节点,然后递归对前半部分和后半部分分别进行归并排序,最后对两个以排好序的链表进行Merge。
public class CzyList {
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public static ListNode sortList(ListNode head) {
if (head == null || head.next == null)
return head;
ListNode f = head.next.next;
ListNode p = head;
while (f != null && f.next != null) {
p = p.next;
f = f.next.next;
}
ListNode temp=p.next;
p.next=null;
ListNode h1=sortList(head);
//p.next=null;
ListNode h2 = sortList(temp);
//p.next = null;//保证每次分半之后 前半都有一个结尾标志null;;;;;;
return merge(h1, h2);
}
public static ListNode merge(ListNode h1, ListNode h2) {
ListNode hn = new ListNode(Integer.MIN_VALUE);
ListNode c = hn;
while (h1 != null && h2 != null) {
if (h1.val < h2.val) {
c.next = h1;
h1 = h1.next;
}
else {
c.next = h2;
h2 = h2.next;
}
c = c.next;
}
if (h1 != null)
c.next = h1;
if (h2 != null)
c.next = h2;
return hn.next;
}
public static void main(String[] args){
ListNode head=new ListNode(6);
head.next=new ListNode(3);
head.next.next=new ListNode(5);
head.next.next.next=new ListNode(4);
head=sortList(head);
while(head!=null){
System.out.println(head.val);
head=head.next;
}
}
}