LeetCode上的Sort List题目:
题目的意思很简单:将一个链表以O(nlogn)的时间复杂度排好序,并且使用常数空间。
关于排序算法的选择:这里我犯了个错误,就是将快速排序的时间复杂度记成了O(nlogn)。。。。(由于对快速排序比较熟悉-,-!)。但是实际情况是如果主元选择不当,最坏的情况会达到O(n2)。而且LeetCode上好像也特意针对快排做了测试用例,所以用快排会TLE。所以要使用归并排序,这种算法性能比较稳定,都是O(nlogn)。
这里做一个补充:虽然归并排序性能比较稳定,但是查资料可知,最常用的还是快排,归并排序的话,需要一定的辅助空间。对于快排,如果随机选择主元的话,快排的最坏情况出现的概率会随数据增多而大大减小,所以一般使用快排。
这里贴出我的代码(包含了快排和归并排序)---------------------(俩算法写了一晚上,想想没脸见人了。。。。)
关于归并的思想是记录本次要排序的链表长度,然后如果长度小于3,就合并,否则就递归排序,之后再合并。注意的地方是一定要先排序右边的链表,这样才能保证preHead的正确性。
/**
* 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) {
ListNode fakeHead = new ListNode(Integer.MIN_VALUE);//To avoid null of the preHead
fakeHead.next = head;
ListNode p = head;
int n = 0;
while(p != null){
n++;
p = p.next;
}
return mergeSort(fakeHead , head , n);
}
public ListNode mergeSort(ListNode preHead , ListNode head , int len){
//如果len为1,2,那么归并为一个list,返回两个list的新head
if(len == 1){
return head;
}
if(len == 2){
if(head.val > head.next.val){
ListNode temp = head.next.next;
preHead.next = head.next;
preHead.next.next = head;
head.next = temp;
}
return preHead.next;
}
//对两个list进行mergeSort
int newLen1 = len / 2;
int newLen2 = len - newLen1;
ListNode p = head;
for(int i = 1 ; i < newLen1 ; i++) {
p = p.next;
}
//Must in the sequence of right----left
ListNode newHead2 = mergeSort(p,p.next,newLen2);
ListNode newHead1 = mergeSort(preHead,head,newLen1);
//Merge
ListNode newHead = null;
if(newHead1.val < newHead2.val){
newHead = newHead1;
newHead1 = newHead1.next;
newLen1--;
}else{
newHead = newHead2;
newHead2 = newHead2.next;
newLen2--;
}
preHead.next = newHead;
while(newLen1 > 0 && newLen2 > 0){
if(newHead1.val < newHead2.val){
newHead.next = newHead1;
newHead1 = newHead1.next;
newHead = newHead.next;
newLen1--;
}else{
newHead.next = newHead2;
newHead2 = newHead2.next;
newHead = newHead.next;
newLen2--;
}
}
if(newLen1 == 0){
newHead.next = newHead2;
}
if(newLen2 == 0){
newHead.next = newHead1;
newLen1--;
//newHead1 = newHead1.next;
while(newLen1 >= 1){
newHead1 = newHead1.next;
newLen1--;
}
newHead1.next = newHead2;
}
return preHead.next;
}
public ListNode quickSort(ListNode head ,ListNode start ,ListNode end){
if(head ==end || head.next == end)
return head;
//choose the first one
ListNode nHead = head;
ListNode previous = head;
ListNode p = head.next;
ListNode npivot = head;
while(true){
if(p == end){
break;
}
if(p.val <= npivot.val){
ListNode temp = p.next;
previous.next = temp;
p.next = nHead;
//npivot.next = temp;
if(start != null)
start.next = p;
nHead = p;
p = temp;
}else{
previous = p;
p = p.next;
}
}
if(start == null)
nHead = quickSort(nHead , start , npivot);
else {
quickSort(nHead, start, npivot);
}
quickSort(npivot.next , npivot , end);
return nHead;
}
///
TEST//
public static void main(String[] args){
Solution obj = new Solution();
ListNode h = obj.create(new int[]{7,5,4,6,3,2,1});
print(h);
h = obj.sortList(h);
print(h);
}
public ListNode create(int[] array){
ListNode temp = new ListNode(array[0]);
ListNode head = temp;
for(int i = 1 ; i < array.length ; i++){
ListNode t = new ListNode(array[i]);
temp.next = t;
temp = t;
}
return head;
}
public static void print(ListNode head){
ListNode p = head;
while(p != null){
System.out.println(p.val);
p = p.next;
}
}
}
class ListNode{
int val;
ListNode next;
public ListNode(int val){
this.val = val;
next = null;
}
}