排序链表有很多种解法,最简单的遍历链表,变成list然后list.sort,再变回有序链表就好了。但是这种做法没有意义,对数据结构没有很好的理解。
1.题目
原题
反转一个单链表。
例子
输入: 4->2->1->3
输出: 1->2->3->4
2.解析
链表排序的写法也很多,比如归并,插入排序都可以,笔者也是一一更新。
2.1归并排序
归并排序用到了递归,想想列表的归并排序,有拆分和归并两部分,拆分不用说了就是递归调用讲列表进行二分,直到不可再分了。并的过程就是将拆分过程中形成的左右两个列表进行大小比较和合并。涉及到链表要考核链表的特点:
- 对于一个新链表的生成,首先初始化一个头部节点,但是不能直接在这个链表上进行next的操作,形成一个大链表。什么意思呢?就是在更新链表指向的时候,用h = h.next这种写法,h本身是在改变的,这个时候要定义一个新链表new和h相同,这样的话h在更新的过程中,new就保留了h的指向,可以生成一个完整的链表。
- 寻找链表的中间节点可以用链表最常用的慢快指针两种做法,慢指针每次走一步,快指针每次走两步,直到快指针走到终点了,慢指针正好走到中间位置,这样的话,就可以获得从中间划分的左右两个链表。
- 但是为了避免循环链表的出现,需要将链表进行切断,这时候需要考虑的是原链表的切断,将head赋给slow,将slow赋给pre,pre更新为slow的位置,pre的next为None,head就从中间切断了。
- 这里还有一个小技巧,为了防止链表报None没有next属性的错误,设置and条件第一个不满足了and后边的就不执行 while fast and fast.next,这是一个不错的技巧。
3.python代码
##归并排序
class Solution:
def merge(self, left, right):
# if not left:
# return right
# if not right:
# return left
out = ListNode(0)
h = out
while left and right:
if left.val < right.val:
h.next = left
left = left.next
else:
h.next = right
right = right.next
h = h.next#为了更新h
h.next = left if left else right
return out.next
def sortList(self, head):
if head is None or head.next is None:
return head
slow = head
fast = head
pre = None
while fast and fast.next:#andzu作用是为了不用到fast.next
pre = slow
slow = slow.next
fast = fast.next.next
mid = slow#slow是重点
pre.next = None
# while mid:
# print('mid',mid.val)
# mid = mid.next
pre.next = None
return self.merge(self.sortList(head), self.sortList(mid))