package com.algorithms; /** * 经典问题: 排序链表 * 在 O(nlogn) 时间复杂度和常数级空间复杂度下,对链表进行排序。 *
* 示例 1: *
* 输入: 4->2->1->3 * 输出: 1->2->3->4 * 示例 2: *
* 输入: -1->5->3->4->0 * 输出: -1->0->3->4->5 *
* 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/sort-list * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 * *
* Created by xifeng.yang on 2020/1/31
*/
public class SortedList {
public static void main(String[] args) {
ListNode head = new ListNode(5);
ListNode node2 = new ListNode(3);
ListNode node3 = new ListNode(2);
ListNode node4 = new ListNode(4);
head.next = node2;
node2.next = node3;
node3.next = node4;
SortedList o = new SortedList();
ListNode newHead = o.sortList(head);
}
private static class ListNode {
int val;
ListNode next;
ListNode(int item) {
val = item;
}
}
/**
* 解法一: 交换结点元素
*
* @param head
* @return
*/
public ListNode sortList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode cur = head;
while (cur != null) {
ListNode next = cur.next;
while (next != null) {
if (next.val < cur.val) {
int temp = next.val;
next.val = cur.val;
cur.val = temp;
}
next = next.next;
}
cur = cur.next;
}
return head;
}
/**
* 执行用时: 321 ms, 在所有 Java 提交中击败了13.48%的用户;
* 内存消耗: 40.6 MB, 在所有 Java 提交中击败了25.11%的用户.
*
* @param head
* @return
*/
public ListNode sortList2(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode cur = head.next;
ListNode pre = head;
while (cur != null) {
if (cur.val < pre.val) {
pre.next = cur.next;
ListNode pre2 = dummyHead;
ListNode cur2 = dummyHead.next;
while (cur.val > cur2.val) {
pre2 = cur2;
cur2 = cur2.next;
}
//把cur节点插入到pre1和cur1之间
pre2.next = cur;
cur.next = cur2;
cur = pre.next;
} else {
//向后移动
pre = cur;
cur = cur.next;
}
}
return dummyHead.next;
}
/**
* 执行用时: 618 ms, 在所有 Java 提交中击败了11.02%的用户,
* 内存消耗: 40.1 MB, 在所有 Java 提交中击败了60.43%的用户.
*/
public ListNode sortList3(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
return quickSort(dummyHead, null);
}
/**
* 解法: 自顶向下的归并排序
* 执行用时: 4 ms, 在所有 Java 提交中击败了81.28%的用户,
* 内存消耗: 40.3 MB, 在所有 Java 提交中击败了45.29%的用户.
*
* @param head
* @return
*/
public ListNode sortList4(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode fast = head.next;
ListNode slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
ListNode mid = slow.next;
slow.next = null;
ListNode left = sortList(head);
ListNode right = sortList(mid);
return merge(left, right);
}
private ListNode merge(ListNode left, ListNode right) {
ListNode newDummy = new ListNode(0);
ListNode tail = newDummy;
while (left != null && right != null) {
if (left.val <= right.val) {
tail.next = left;
left = left.next;
} else {
tail.next = right;
right = right.next;
}
tail = tail.next;
}
tail.next = left != null ? left : right;
return newDummy.next;
}
public ListNode sortList5(ListNode head) {
if (head == null || head.next == null) {
return head;
}
int len = 0;
while (head != null) {
len++;
head = head.next;
}
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
for (int step = 1; step < len; step *= 2) {
//从lo起所剩元素>step时才需要进行merge.
for (int lo = 0; lo < len - step; lo += step * 2) {
}
}
return dummyHead.next;
}
/**
* 解法: 自底向上的归并排序.
* 执行用时: 10 ms, 在所有 Java 提交中击败了27.36%的用户;
* 内存消耗: 40.6 MB, 在所有 Java 提交中击败了25.93%的用户.
*
* @param head
* @return
*/
public ListNode sortListOld(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode cur, h1, h2, pre;
cur = head;
int length = 0;
while (cur != null) {
cur = cur.next;
length++;
}
ListNode dummy = new ListNode(0);
dummy.next = head;
for (int step = 1; step < length; step *= 2) {
pre = dummy;
cur = dummy.next;
while (cur != null) {
int i = step;
h1 = cur;
while (i > 0 && cur != null) {
cur = cur.next;
i--;
}
if (i > 0 || cur == null) {
//从cur到尾部<=step个结点.
break;
}
i = step;
h2 = cur;
while (i > 0 && cur != null) {
cur = cur.next;
i--;
}
int c1 = step;
//i>0表示从h2起到尾部