输入:1->2->3->4->5->6->7
输出:1->7->2->6->3->5->4
或者
输入:1->2->3->4->5->6
输出:1->6->2->5->3->4
思路:
1. 将1->2->3->4->5->6->7分成:1->2->3 与 4->5->6->7,将后半部分逆序7->6->5->4
2. 合并1->2->3与7->6->5->4 为1->7->2->6->3->5->4
3. 划分:就是找到中间节点mid,作为后半部分的头节点(注意后半部分的节点数量会比前半部分多0个或者1个节点),这里引入了slow与fast两个外部变量,fast一次走2步,slow一次走一步,这样fast走完时,slow正好走了一半,从而找到中间节点,同时,还需引入slow_pre外部变量,作为slow的前一个节点,目的是为了找到中间节点的slow时,通过slow_pre.next = None的方式,断开链表,分成2个链表
4. 逆序:输入后半段的头节点,也就是mid,实现对链表逆序操作,可参考之前的文章,此处采用插入法逆序(链表逆序)
5. 合并:引入外部变量cur1, cur2用来操作两个链表,每个节点仍然是2次指针操作,但要注意,每节点指针操作结束后,需要将外部操作变量cur下移。最后当cur1遍历结束,即cur1.next为None时,跳出循环,将cur1.next指向cur2,cur2为最后一个节点。
代码:
def find_mid_node(head):
# 头节点为空,或者链表为单节点,直接返回
if head is None or head.next is None:
return head
fast = head
slow = head
slow_pre = head
while fast is not None and fast.next is not None:
slow_pre = slow
slow = slow.next # 每次移动1个节点,当fast结束时,slow走了一半
fast = fast.next.next # 每次隔一个赋值,一步走2个节点
# 需要把指向slow的指针断了,这样才能变成两个链表,即slow前一个节点的next指针为空
slow_pre.next = None
return slow # slow走了链表的一半,返回的值就是中间节点mid
def reverse(head):
if head is None or head.next is None:
return head
cur = head
pre = None
while cur:
nex = cur.next
cur.next = pre
pre = cur
cur = nex
head = pre
return head
def reorder(head):
if head is None or head.next is None:
return head
cur1 = head
mid = find_mid_node(head)
cur2 = reverse(mid)
# 两个链表长度相等或者差1个,只需用cur1.next作为循环条件,遍历
while cur1.next is not None:
#对链表1的节点2次指针操作
tmp = cur1.next
cur1.next = cur2
cur1 = tmp
#对链表2的节点2次指针操作
tmp = cur2.next
cur2.next = cur1
cur2 = tmp
# cur1.next为空,跳出循环,指向最后一个cur2节点
cur1.next = cur2
return cur1
# 测试
if __name__ == "__main__":
link = LinkedList()
print("========== before ============")
link.add(1)
link.add(2)
link.add(3)
link.add(4)
link.add(5)
link.add(6)
link.print_link()
print("========== after ============")
reorder(link.head)
link.print_link()
#结果
========== before ============
1
2
3
4
5
6
========== after ============
1
6
2
5
3
4