https://leetcode.cn/problems/sort-list/?envType=study-plan-v2&envId=top-interview-150
采用分治思想解决这题,每次合并长度为1\2\4…的链表,合并思想和合并有序链表一致,单独写成一个函数即可。
合并思路如下:
while(分治长度)
定义一个头节点节点方便链表连接
while(每两个链表进行合并)
进行遍历取到左边一个链表
链表末尾指空
进行遍历取到右边一个链表
链表末尾指空
两个链表合并
头节点连接到这个链表
头节点指向这个链表的尾部
具体代码如下:
class Solution {
public ListNode sortList(ListNode head) {
int length = 0;
//先计算链表的长度
ListNode listNode = head;
while(listNode!=null){
length++;
listNode = listNode.next;
}
ListNode dummyHead = new ListNode(0,head);
for(int subLength=1;subLength<length;subLength*=2){
//从长度为1的链表开始合并
//分别求出两个合并节;
//排序后的链表需要接上前面的
ListNode pre = dummyHead;
ListNode curr = dummyHead.next;
while(curr!=null){
//这里的做法非常复杂
ListNode head1 = curr;
for (int i = 1; i < subLength && curr.next != null; i++)
curr = curr.next;
//先把这个链表的下一个节点记下来,然后直接让最后一个节点指空
//让当前链表独立出来
ListNode head2 = curr.next;
curr.next = null;
curr = head2;
//可能由于长度的问题导致了第二个节点找不到了直接判空
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;
}
ListNode merged = merge(head1,head2);
pre.next = merged;
//将这个前置节点放到排序后的链表的最后一个
while(pre.next!=null){
pre = pre.next;
}
//节点后移动,排序后的链表连接全靠pre
curr= next;
}
}
return dummyHead.next;
}
public ListNode merge(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;
}
}