归并排序


归并排序思路

   1)找到单链表中间节点,从而将原链表分为左右两部分;

   2)对左右两部分链表分别进行归并排序,并合并左右两部分;

   3)分别对两部分重复上述操作,直到所有元素都已排序成功。

   因为单链表只能从链表头节点向后遍历,第一步操作用快慢指针找链表中点的时间复杂度就为O(n)。由于之后都是分别对两部分完成上述操作,因此会将链表划分为logn个段,因此时间复杂度为O(nlogn) 。

图解示意

1、以[4,2,5,3,7,9,0,1]为例,模拟归并的过程:

两两归并,划分成:[4,2]、[5,3]、[7,9]、[0,1]

组内升序排:[2,4]、[3,5]、[7,9]、[0,1]

第一趟归并后结果如下:

2 4 3 5 7 9 0 1

2、在上一趟归并的基础上再做两两归并,划分成:[2,4,3,5]、[7,9,0,1]

组内升序排:[2,3,4,5]、[0,1,7,9]

第二趟归并后结果如下:

2 3 4 5 0 1 7 9

3、在上一趟归并的基础上再做两两归并,划分成[2,3,4,5,0,1,7,9]

组内升序排:[0,1,2,3,4,5,7,9]

第三趟归并后结果如下:

0 1 2 3 4 5 7 9

代码

class LinkList(object):
    # 单链表归并排序
    def mergeSort(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or not head.next:
            return head
        # 用快慢指针找链表中间节点,循环结束时:slow.next指向中间节点。
        slow, fast = head, head
        while fast.next and fast.next.next:
            slow = slow.next
            fast = fast.next.next
        # 对右半部分归并排序
        right = self.mergeSort(slow.next)
        # 断开左右两部分链表
        slow.next = None
        # 对左半部分归并排序
        left = self.mergeSort(head)
        return self.mergeLink(left, right)

    # 合并两个链表:按升序
    def mergeLink(self, left, right):
        node = ListNode(-1)
        head = node
        while left and right:
            if left.val < right.val:
                node.next = left
                left = left.next
            else:
                node.next = right
                right = right.next
            node = node.next
        node.next = left if left else right
        return head.next

运行截图:

原文地址:https://www.cnblogs.com/panweiwei/p/12898022.html