问题描述:
Sort a linked list using insertion sort.
原问题链接:https://leetcode.com/problems/sort-list/
问题分析
有时候,往往是一些看似简单的问题描述 ,其解决方法越麻烦。这里问题描述确实简单,对于一个链表来说,我们需要寻找一种时间复杂度为O(NlogN)的排序法。对于数组来说,要找到这种时间复杂度的方法有好几种,比如说归并排序,快速排序,堆排序等。这些都是建立在基于数组的索引访问很方便的基础之上的。
可是对于链表来说,这又是一个要命的问题。它最方便的访问法就是只能从头往后一个个的访问下去。如果要访问到其中的某个索引位置则相对慢很多。看来我们需要从上述的几种方法中找一种对于索引访问比较少,这样使得方法的性能没有太大影响的才行。
我们可以考虑归并排序,它是递归的将一组元素划分成两个部分,一直到无法继续划分位置。然后在递归返回的时候将相邻的两个部分给合并起来。在这里,我们可以将链表首先划分成两个部分。这里可以采用前面快慢指针的手法。这样就得到了两个链表。
然后我们再针对两个链表进行合并。而合并链表的手法在之前的一些方法里也有过讨论,我们就是建立一个临时节点,然后将它们两个链表按照大小往里面加。同时每次也移动新链表里元素的节点。
这样,把这两个点解决之后,就好办了。我们可以得到如下的详细代码实现:
/** * Definition for singly-linked list. * class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; * next = null; * } * } */ public class Solution { public ListNode sortList(ListNode head) { if(head == null || head.next == null) return head; ListNode fast = head, slow = head, pre = null; while(fast != null && fast.next != null) { pre = slow; slow = slow.next; fast = fast.next.next; } pre.next = null; ListNode first = sortList(head); ListNode second = sortList(slow); return merge(first, second); } private ListNode merge(ListNode first, ListNode second) { ListNode dummy = new ListNode(0); ListNode pre = dummy; while(first != null && second != null) { if(first.val < second.val) { pre.next = first; first = first.next; } else { pre.next = second; second = second.next; } pre = pre.next; } if(first != null) pre.next = first; if(second != null) pre.next = second; return dummy.next; } }