题目描述:
给定链表:L0->L1->L2…->Ln,把链表重新排序为L0->Ln->L1->L(n-1)…
要求:
(1) 在原来链表的基础上进行排序,即不能申请新的结点;
(2)只能修改结点的next域,不能修改数据域。
思路:
- 首先找到链表的中间结点;
- 对链表的后半部分子链表进行逆序;
- 把链表的前半部分子链表与逆序后的后半部分子链表进行合并,合并的思路为:分别从两个链表各取一个结点进行合并。
实现方法如下图:
算法性能分析:
查找链表中间结点的方法的时间复杂度为O(n),逆序子链表的时间复杂度为O(n),合并两个子链表的时间复杂度也为O(n),因此,整个方法的时间复杂度为O(n);
由于这种方法只用了常数个额外指针变量,所以空间复杂度为O(1)
代码实现:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2020/1/16 15:07
# @Author : buu
# @Software: PyCharm
# @Blog :https://blog.csdn.net/weixin_44321080
class LNode:
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def FindMiddleNode(head):
"""
用快慢指针法找到链表Head的中间结点,把链表从中间断成两个子链表
:param head: 链表头结点
:return: 链表中间结点
"""
if head is None or head.next is None:
return head
fast = head # 快指针,遍历链表时每次走两步
slow = head # 满指针,遍历链表时每次走一步
slowPre = head # 当fast指针到达链表尾时,slow恰好指向链表的中间结点
while fast is not None and fast.next is not None:
slowPre = slow # slowPre存在是为了把链表截断
slow = slow.next
fast = fast.next.next
slowPre.next = None # 把链表断开成两个独立的子链表
return slow
def Reverse(head):
"""
对不带头结点的但链表逆序
:param head: 链表首结点
:return: 逆序后的首结点
"""
if head is None or head.next is None:
return head
pre = head # 前驱结点,此时head为首结点,而非头结点
cur = head.next # 当前结点
next = cur.next # 后继结点
pre.next = None # 此时pre指向首结点,所以逆转后满足pre.next=None
while cur is not None:
next = cur.next
cur.next = pre
pre = cur
cur = cur.next
cur = next
return pre
def Reorder(head):
"""
对链表进行排序
:param head: 链表头结点
:return:
"""
if head is None or head.next is None:
return
cur1 = head.next # 前半部分链表第一个结点
mid = FindMiddleNode(head.next)
cur2 = Reverse(mid) # 后半部分链表逆序后的第一个结点
tmp = None
while cur1.next is not None: # 合并两个链表
tmp = cur1.next # tmp 用来做连接的中间结点
cur1.next = cur2
cur1 = tmp
tmp = cur2.next
cur2.next = cur1
cur2 = tmp
cur1.next = cur2
if __name__ == '__main__':
i = 1
head = LNode()
tmp = None
cur = head
while i < 8: # 构造第一个链表
tmp = LNode()
tmp.data = i
cur.next = tmp
cur = tmp
i += 1
print('before reorder:', end=' ')
cur = head.next
while cur is not None:
print(cur.data, end=' ')
cur = cur.next
# middleNode=FindMiddleNode(head) # 测试中间结点及之后链表
# print('\nafter: ',end=' ')
# while middleNode is not None:
# print(middleNode.data,end=' ')
# middleNode=middleNode.next
print('\nafter reorder:', end=' ')
Reorder(head)
cur = head.next
while cur is not None:
print(cur.data, end=' ')
cur = cur.next
结果:
引申:
如何查找链表的中间结点
主要思路:
用两个指针从链表的第一个结点开始同时遍历结点,一个快指针每次走2步,另外一个慢指针每次走1步;当快指针先到链表尾部时,慢指针则恰好到达链表中部。(快指针到链表尾部时,当链表长度为奇数时,慢指针指向的即是链表中间指针;当链表长度为偶数时,慢指针指向的结点和慢指针指向的下一个结点都是链表的中间结点)
end
扫描二维码关注公众号,回复:
8930685 查看本文章