【LeetCode 148. 排序链表】归并排序和快速排序

148. 排序链表

快速排序

用快速排序时,将中间节点当作pivot比结尾节点快,下图分别为中间节点和尾节点的运行结果。

class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) return head;
        ListNode tail = head;
        while (tail.next != null) {
            tail = tail.next;
        }
        return quickSort(head, tail);
    }

    public ListNode quickSort(ListNode head, ListNode tail) {
        ListNode saveTail = tail.next;
        ListNode smallDummy = new ListNode(-1), largeDummy = new ListNode(-1), equalDummy = new ListNode(-1);
        // 注意equal的节点不止一个
        ListNode small = smallDummy, large = largeDummy, equal = equalDummy;
        // 找中点
        ListNode fast = head, slow = head;
        // 注意结尾不是null而是tail.next
        while (fast != saveTail && fast.next != saveTail) {
            fast = fast.next.next;
            slow = slow.next;
        }
        while (true) {
            ListNode tmp = head.next;
            head.next = null;
            if (head.val == slow.val) {
                equal.next = head;
                equal = equal.next;
            } else if (head.val < slow.val) {
                small.next = head;
                small = small.next;
            } else {
                large.next = head;
                large = large.next;
            }
            if (head == tail) break;
            head = tmp;
        }
        small.next = equalDummy.next;
        equal.next = largeDummy.next;
        // 注意把尾巴接上
        large.next = saveTail;
        ListNode node1 = small, node2 = large;
        if (small == smallDummy) {
            node1 = smallDummy.next;
        } else {
            node1 = quickSort(smallDummy.next, small);
        }
        if (large == largeDummy) {
            node2 = largeDummy.next;
        } else {
            node2 = quickSort(largeDummy.next, large);
        }
        // 注意拼接
        equal.next = node2;
        return node1;
    }
}

归并(自顶向下)

提交之后发现自顶向下的结果比自底向上的快2ms。

class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) return head;
        ListNode pre = getMid(head), mid = pre.next;
        // 注意要断开左右两边的链表
        pre.next = null;
        ListNode l1 = sortList(head);
        ListNode l2 = sortList(mid);
        return merge(l1, l2);
    }

    public ListNode getMid(ListNode head) {
        // slow指向了中点或者右中点
        // 所以要记下slow之前的指针
        ListNode fast = head, slow = head, pre = null;
        // 因为每次左右两边都断开了, 所以tail为null
        while (fast != null && fast.next != null) {
            pre = slow;
            fast = fast.next.next;
            slow = slow.next;
        }
        return pre;
    }

    public ListNode merge(ListNode l1, ListNode l2) {
        ListNode dummyNode = new ListNode(-1), cur = dummyNode;
        while (l1 != null && l2 != null) {
            if (l1.val <= l2.val) {
                cur.next = l1;
                l1 = l1.next;
            } else if (l1.val > l2.val) {
                cur.next = l2;
                l2 = l2.next;
            }
            cur = cur.next;
        }
        // 注意把剩下的链表接上
        cur.next = l1 == null ? l2 : l1;
        return dummyNode.next;
    }
}

归并(自底向上)

class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) return head;
        int length = 0;
        ListNode cur = head;
        while (cur != null) {
            cur = cur.next;
            length++;
        }
        ListNode dummyNode = new ListNode(-1, head);
        for (int subLength = 1; subLength < length; subLength = subLength << 1) {
            ListNode prev = dummyNode;
            // 注意cur要是每次排序后的新的head
            cur = dummyNode.next;
            while (cur != null) {
                ListNode head1 = cur;
                // 注意要判断cur.next!=null
                for (int i = 1; i < subLength && cur != null && cur.next != null; i++) {
                    cur = cur.next;
                }
                // 如果上面不判断cur.next!=null
                // for结束条件为cur==null, cur.next会报错
                ListNode head2 = cur.next;
                // 断开两个链表
                cur.next = null;
                // 重新赋值给cur
                cur = head2;
                // 找到下一个开始位置
                for (int i = 1; i < subLength && cur != null && cur.next != null; i++) {
                    cur = cur.next;
                }
                //断开subLength*2之后的位置
                ListNode next = null;
                // 这里的cur可能为null(当head2为空时)
                if (cur != null) {
                    next = cur.next;
                    cur.next = null;
                }
                // 合并
                ListNode merged = merge(head1, head2);
                prev.next = merged;
                // 移动到subLength*2之后的位置
                while (prev.next != null) prev = prev.next;
                cur = next;
            }
        }
        return dummyNode.next;
    }

    public ListNode merge(ListNode l1, ListNode l2) {
        ListNode dummyNode = new ListNode(-1), cur = dummyNode;
        while (l1 != null && l2 != null) {
            if (l1.val <= l2.val) {
                cur.next = l1;
                l1 = l1.next;
            } else if (l1.val > l2.val) {
                cur.next = l2;
                l2 = l2.next;
            }
            cur = cur.next;
        }
        // 注意把剩下的链表接上
        cur.next = l1 == null ? l2 : l1;
        return dummyNode.next;
    }
}
posted @ 2022-03-18 12:48  wuzu  阅读(25)  评论(0编辑  收藏  举报