给定一个乱序的链表,要求将链表进行排序后然后返回头结点,要求时间复杂度为 O(nlogn)。
leetcode
- 由于无法快速得到链表中某一节点得值,时间复杂度为 O(nlogn),所以,通过归并排序。
- 归并的核心思想是将数据分为两段有序的数据,再进行合并。
- 归并的程序设计上可以由递归和迭代两种方法,迭代稍微复杂一些,需要计算每次段的长度。递归就利用分治的思想,每次将数据分为两段。
首先是迭代方法。
/**
* created by lippon
*/
class Solution {
public ListNode sortList(ListNode head) {
int n = 0;
// 定义一个虚拟节点,因为头节点会改变,所以,通过虚拟节点来指向头节点
// 最后返回虚拟节点的下一节点即为头节点
ListNode dummy = new ListNode(0);
dummy.next= head;
// 计算链表长度
ListNode cur = head;
while(cur != null) {
cur = cur.next;
n ++;
}
// 计算每次归并的长度,由小变大
for(int i = 1; i < n; i *= 2) {
// 将当前指针指向头
cur = dummy;
// 计算归并段的起始位置
for(int j = 0; j + i < n; j += 2 * i){
// 定义前后两个节点的位置
int x = 0, y = 0;
// 定义前后两个节点
ListNode first = cur.next;
ListNode second = cur.next;
// 将后指针送到后半段
int temp = 0;
while(temp < i && second != null) {
temp ++;
second = second.next;
}
// 前后两个节点都没超出段的情况下,将当前指针不断指向小的节点
// 这里需要注意的是后节点可能会超出链表长度
while(x < i && y < i && second != null) {
if(first.val < second.val) {
cur.next = first;
first = first.next;
cur = cur.next;
x ++;
} else {
cur.next = second;
second = second.next;
cur = cur.next;
y ++;
}
}
// 接上剩余的节点
while(x < i) {
cur.next = first;
first = first.next;
cur = cur.next;
x ++;
}
while(y < i && second != null) {
cur.next = second;
second = second.next;
cur = cur.next;
y ++;
}
// 将当前节点接到下一段
cur.next = second;
}
}
return dummy.next;
}
}
递归方法
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){
fast = fast.next.next;
pre = slow;
slow = slow.next;
}
// head --->pre--->slow--->fast
pre.next = null;
// 分治前半部分 head ---> pre
ListNode l1 = sortList(head);
// 分治后半部分 slow ---> fast
ListNode l2 = sortList(slow);
// 将两个有序链表 l1,l2 归并
return merge(l1,l2);
}
public ListNode merge(ListNode l1,ListNode l2){
ListNode head = null,p = null;
while(l1!=null && l2 != null){
ListNode node;
if(l1.val<l2.val){
node=l1;
l1=l1.next;
}else{
node = l2;
l2 = l2.next;
}
if(p == null){
head = node;
}else{
p.next = node;
}
p=node;
}
if(l1 != null){
p.next = l1;
}
if(l2 != null){
p.next = l2;
}
return head;
}
}