自顶向下归并排序
- 用快慢指针找到序列中间位置
这里要注意一个细节:始终使fast指向链表尾节点的next节点(也就是null),这样slow指向后半段链表的起点,避免出现死循环。
前半段链表[head, slow)
,后半段[slow, fast)
- 合并两个排序链表(从底层递归回顶层时,返回的链表一定是排好序的)
自顶向下归并排序
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode sortList(ListNode head) {
return sort(head, null);
}
public ListNode sort(ListNode head, ListNode tail) {
if(head == null) return null;
if(head.next == tail) {
head.next = null;
return head;
}
ListNode dummy = new ListNode(0, head);
ListNode fast, slow;
fast = slow = dummy;
while(fast != tail && fast.next != tail) {
slow = slow.next;
fast = fast.next.next;
}
if(fast != null) slow = slow.next;
ListNode mid = slow;
return merge(sort(head, mid), sort(mid, tail));
}
public ListNode merge(ListNode h1, ListNode h2) {
if(h1 == null) return h2;
if(h2 == null) return h1;
ListNode dummy = new ListNode(0);
ListNode res = dummy;
while(h1 != null && h2 != null) {
if(h1.val <= h2.val) {
res.next = h1;
h1 = h1.next;
} else {
res.next = h2;
h2 = h2.next;
}
res = res.next;
}
if(h1 != null) res.next = h1;
else res.next = h2;
return dummy.next;
}
}
自底向上排序
相当于省略自顶向下方法的递归过程,直接从底层开始向上两两合并。
最底层子链表的长度最长为1,子链表长度每合并一次,最长长度变为上一层长度的两倍
- 遍历链表长度[1, len),对于每一层:
- 找到要合并的两个子链表的表头,将子链表与原链表断开连接
这里定义ListNode cut(ListNode head, int len)
函数,截断从head开始长度为len的链表(截断的意思是将这段子链表尾链表的next设置为null),从而得到子链表的表头和表尾 - 合并两个子链表
- 更新合并链表的连接
- 循环2、3、4步
- 空间复杂度O(1)
- 时间复杂度O(logn)
自底向上排序
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode sortList(ListNode head) {
if(head == null) return head;
int L = 0;
ListNode tmp = head;
while(tmp != null) {
tmp = tmp.next;
++ L;
}
ListNode dummy = new ListNode(0, head);
for(int len = 1; len < L; len <<= 1) {
ListNode cur = dummy.next;
ListNode pre = dummy;
while(cur != null) {
// [head1, head2) [head2, next)
ListNode head1 = cur;
ListNode head2 = cut(head1, len);
ListNode next = cut(head2, len);
cur = next;
pre.next = merge(head1, head2);
while(pre.next != null) {
pre = pre.next;
}
}
}
return dummy.next;
}
/* 截断从head开始长度为len的链表,返回链表尾节点的next节点 */
public ListNode cut(ListNode head, int len) {
-- len; //从head开始长度为len的链表尾节点需要从head跳len-1次
while(head != null && len -- > 0) {
head = head.next;
}
ListNode res = null;
if(head != null) {
res = head.next;
head.next = null;
}
return res;
}
public ListNode merge(ListNode h1, ListNode h2) {
if(h1 == null) return h2;
if(h2 == null) return h1;
ListNode dummy = new ListNode(0);
ListNode res = dummy;
while(h1 != null && h2 != null) {
if(h1.val <= h2.val) {
res.next = h1;
h1 = h1.next;
} else {
res.next = h2;
h2 = h2.next;
}
res = res.next;
}
if(h1 != null) res.next = h1;
else res.next = h2;
return dummy.next;
}
}
优先队列方法
- 把链表数值全部放进优先队列中
- 依次读取队首元素构建升序链表
优先队列排序Integer
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode sortList(ListNode head) {
Queue<Integer> pq = new PriorityQueue<>((o1, o2) -> {
return o1 - o2;
});
while(head != null) {
pq.offer(head.val);
head = head.next;
}
ListNode dummy = new ListNode(0);
ListNode res = dummy;
while(!pq.isEmpty()) {
int val = pq.poll();
res.next = new ListNode(val);
res = res.next;
}
return dummy.next;
}
}
- 将链表节点放进优先队列中
- 依次读取队首链表节点,重新构建链表的连接关系
优先队列排序ListNode
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode sortList(ListNode head) {
Queue<ListNode> pq = new PriorityQueue<>((o1, o2) -> {
return o1.val - o2.val;
});
while(head != null) {
pq.offer(head);
head = head.next;
}
ListNode dummy = new ListNode(0);
ListNode res = dummy;
while(!pq.isEmpty()) {
res.next = pq.poll();
res = res.next;
res.next = null;
}
return dummy.next;
}
}