针对本题排序流程,主要是将链表拆分为长度为subLength的子链表1和子链表2,然后把子链表1和子链表2合并为一条有序链表,重复上述步骤直到把链表都拆分完,这样这条链表每段长度为2的子链表都是有序的,那么要整条链表有序,我们只需要把subLength扩大并重复上述排序步骤即可,也就是每次拆分排序完subLength = subLength * 2后再次进行拆分排序,直到subLength大于或者等于整条链表的长度,画草图如下所示
代码如下,每行都有解释
class Solution {
public ListNode sortList(ListNode head) {
if (head == null) {
return head;
}
int length = 0;
ListNode node = head;
// 计算链表总长度
while (node != null) {
length++;
node = node.next;
}
// 定义一个头节点指向链表
ListNode dummyHead = new ListNode(0, head);
// subLength表示子链表长度,subLength <<= 1 是 subLength = subLength * 2 的意思
// 这样写的目的是把链表分成多个子链表进行多次合并有序链表操作,比如两条长度为1的子链表合并变成一条长度为2的有序链表,
// 两条长度为2的子链表合并变成一条长度为4的有序链表,以此类推直到子链表长度大于或者等于链表长度即排序完成
for (int subLength = 1; subLength < length; subLength <<= 1) {
// 定义pre指针,指向已拆分子链表尾结点,用于连接有序子链表,curr用于遍历链表,并指向待拆分链表头结点
ListNode prev = dummyHead, curr = dummyHead.next;
// 如果没有子链表了,即curr指向null则结束本次循环
while (curr != null) {
// 第一条子链表的头结点
ListNode head1 = curr;
// 按subLength拆分为一条长度为subLength的子链表
for (int i = 1; i < subLength && curr.next != null; i++) {
curr = curr.next;
}
// 第二条子链表头结点
ListNode head2 = curr.next;
curr.next = null;
curr = head2;
// 按subLength拆分为一条长度为subLength的子链表
for (int i = 1; i < subLength && curr != null && curr.next != null; i++) {
curr = curr.next;
}
// 定义指向待拆分链表头结点的指针
ListNode next = null;
if (curr != null) {
next = curr.next;
curr.next = null;
}
// 合并上面拆分出来的两条长度为subLength的子链表
ListNode merged = merged(head1, head2);
prev.next = merged;
// 遍历合并后的有序子链表,prev指向该链表的尾结点
while (prev.next != null) {
prev = prev.next;
}
// curr指向待拆分链表头结点,以便继续进行拆分
curr = next;
}
}
return dummyHead.next;
}
// 合并两条有序链表为一条有序链表
public ListNode merged(ListNode head1, ListNode head2) {
ListNode dummyHead = new ListNode(0);
ListNode temp = dummyHead, temp1 = head1, temp2 = head2;
// 新建一条链表,遍历两条链表并比较其结点值大小,新建链表指针每次指向较小的那个结点,
// 直到其中一条链表遍历结束则结束循环
while (temp1 != null && temp2 != null) {
if (temp1.val <= temp2.val) {
temp.next = temp1;
temp1 = temp1.next;
} else {
temp.next = temp2;
temp2 = temp2.next;
}
temp = temp.next;
}
// 如果其中一条链表比另外一条链表更长,那么那条更长的链表剩余的结点就是最大的几个结点,直接连接即可
if (temp1 != null) {
temp.next = temp1;
} else if (temp2 != null) {
temp.next = temp2;
}
return dummyHead.next;
}
}
题目链接:题单 - 力扣(LeetCode)全球极客挚爱的技术成长平台