归并排序思路
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
运行截图: