[英]reverse a linked list in groups
我现在正在研究分组反转链表,但遇到了一些问题。
问题是:
给定一个具有“n”个节点的 LinkedList,根据其大小按以下方式反转它:
如果“n”是偶数,则在一组 n/2 个节点中反转列表。 如果 n 为奇数,则保持中间节点不变,反转前 'n/2' 个节点并反转最后 'n/2' 个节点。
我的做法是:
def lenLinkedlist(head):
count = 0
current = head
while current:
current = current.next
count += 1
return count
def reverseInGroupPart(head, n):
count = 0
previous, current, next = None, head, None
while current and count < n//2:
next = current.next
current.next = previous
previous = current
current = next
count += 1
# even
if n%2 == 0:
# current at middle right now
# head supports to be middle now
head.next = reverseInGroupPart(current, n)
# odd
else:
# current at middle now
head.next = current
current.next = reverseInGroupPart(current.next, n)
return previous
def reverseGroups(head):
n = lenLinkedlist(head)
if n%2 == 0:
return reverseInGroupPart(head, n)
else:
return reverseInGroupPart(head, n)
class Node:
def __init__(self, _value, _next = None):
self.value = _value
self.next = _next
def print_list(self):
temp = self
while temp:
print(temp.value, end = ' ')
temp = temp.next
print()
def main():
head = Node(1)
head.next = Node(2)
head.next.next = Node(3)
head.next.next.next = Node(4)
head.next.next.next.next = Node(5)
head.next.next.next.next.next = Node(6)
print('original linked list is: ', end = '')
head.print_list()
result = reverseGroups(head)
print('reverse of linked list is ', end = '')
result.print_list()
main()
有错误:
Traceback (most recent call last):
File "/Users/PycharmProjects/tester/main.py", line 62, in <module>
main()
File "/Users/PycharmProjects/tester/main.py", line 58, in main
result = reverseGroups(head)
File "/Users/PycharmProjects/tester/main.py", line 33, in reverseGroups
return reverseInGroupPart(head, n)
File "/Users/PycharmProjects/tester/main.py", line 22, in reverseInGroupPart
head.next = reverseInGroupPart(current, n)
File "/Users/PycharmProjects/tester/main.py", line 22, in reverseInGroupPart
head.next = reverseInGroupPart(current, n)
File "/Users/PycharmProjects/tester/main.py", line 22, in reverseInGroupPart
head.next = reverseInGroupPart(current, n)
[Previous line repeated 993 more times]
File "/Users/PycharmProjects/tester/main.py", line 19, in reverseInGroupPart
if n%2 == 0:
RecursionError: maximum recursion depth exceeded in comparison
original linked list is: 1 2 3 4 5 6
Process finished with exit code 1
我尝试使用递归方法来解决问题,但不确定是什么导致了错误。 谢谢。
您的reverseGroups()
function 没有多大意义,因为它有一个if
在两个分支中都做同样的事情。
我将采取不同的方法。 首先,我将把你的函数改为Node
的方法。 接下来,我将让这些方法中的大多数递归,只是为了练习。 最后,我将使链表段的反转递归,但不是重新排列链表部分的更高级别的逻辑,因为这似乎不是一个递归问题:
class Node:
def __init__(self, value, _next=None):
self.value = value
self.next = _next
def printLinkedlist(self):
print(self.value, end=' ')
if self.next:
self.next.printLinkedlist()
else:
print()
def lengthLinkedlist(self):
count = 1
if self.next:
count += self.next.lengthLinkedlist()
return count
def reverseLinkedList(self, length):
head, rest = self, self.next
if length > 1:
if rest:
head, rest = rest.reverseLinkedList(length - 1)
self.next.next = self
self.next = None
return head, rest
def reverseGroups(self):
head = self
length = self.lengthLinkedlist()
if length > 3:
tail = self
head, rest = self.reverseLinkedList(length//2) # left
if length % 2 == 1: # odd, skip over middle
tail.next = rest
tail = tail.next
rest = tail.next
tail.next, _ = rest.reverseLinkedList(length//2) # right
return head
if __name__ == '__main__':
head = Node(1)
head.next = Node(2)
head.next.next = Node(3)
head.next.next.next = Node(4)
head.next.next.next.next = Node(5)
head.next.next.next.next.next = Node(6)
head.next.next.next.next.next.next = Node(7)
print('original linked list is: ', end='')
head.printLinkedlist()
head = head.reverseGroups()
print('reverse of linked list is ', end='')
head.printLinkedlist()
OUTPUT
> python3 test.py
original linked list is: 1 2 3 4 5 6 7
reverse of linked list is 3 2 1 4 7 6 5
>
如果我们注释掉最后一个链接:
# head.next.next.next.next.next.next = Node(7)
那么我们的output就是:
> python3 test.py
original linked list is: 1 2 3 4 5 6
reverse of linked list is 3 2 1 6 5 4
>
对我来说,这个问题原来是一个仔细的簿记。 我还必须首先迭代地实现reverseLinkedList()
,让reverseGroups()
工作,然后返回 go 并递归地重新实现reverseLinkedList()
。
我会分小步解决这个问题。 对于初学者,class 结构可以进行一些大修以使其更易于使用。 我会创建一个LinkedList
class 并利用__repr__
、 __len__
和__iter__
之类的 dunder 方法来使代码更简洁、更 Pythonic。 根据PEP-8使用snake_case
而不是camelCase
。
from functools import reduce
class Node:
def __init__(self, value, next_=None):
self.value = value
self.next = next_
def __repr__(self):
return str(self.value)
class LinkedList:
def __init__(self, els):
self.head = None
for e in reversed(els):
self.head = Node(e, self.head)
def __iter__(self):
curr = self.head
while curr:
yield curr
curr = curr.next
def __getitem__(self, i):
try:
return list(zip(self, range(i + 1)))[-1][0]
except IndexError:
raise IndexError(i)
def __len__(self): # possibly better to cache instead of compute on the fly
return reduce(lambda a, _: a + 1, self, 0)
def __repr__(self):
return "[" + "->".join([str(x) for x in self]) + "]"
if __name__ == "__main__":
for length in range(8):
ll = LinkedList(list(range(length)))
print("original:", ll)
在深入研究算法之前,我应该注意链表不适合递归(除非语言是尾调用优化的),因为每个递归步骤只会将问题空间减少 1 个节点。 这会产生大量的调用开销,如果列表有超过 1000 个元素,并且通常不会提供太多的优雅/可读性来抵消这些缺点,则可能会导致堆栈崩溃。
另一方面,树更适合递归,因为在遍历平衡良好的树期间调用堆栈经常弹出,将深度保持在对数而不是线性比例。 对于使用快速排序或合并排序或执行二进制搜索对列表进行排序也是如此。
链表算法也往往需要对前一个和下一个节点的许多引用,以及用于虚拟头和尾的簿记节点,state 在离散堆栈帧中不容易访问。 迭代地,您可以直接从循环块访问您需要的所有 state,无需参数。
也就是说,这是一个简单的迭代反转例程,我将用作编写代码的 rest 的基础:
class LinkedList:
# ...
def reverse(self):
prev = None
curr = self.head
while curr:
nxt = curr.next
curr.next = prev
prev = curr
curr = nxt
self.head = prev
这需要更通用:如果我可以重构此算法以反转节点和子列表长度之间的列表子集,那么问题就基本解决了,因为我们可以将此算法应用于列表的前半部分和后半部分分别地。
第一步是避免硬编码self.head
并将其作为参数传递,返回反向子列表的新头。 这仍然存在(我认为这是一个要求):
class LinkedList:
# ...
def _reverse_from(self, curr):
prev = None
while curr:
nxt = curr.next
curr.next = prev
prev = curr
curr = nxt
return prev
def reverse(self):
self.head = self.reverse_from(self.head)
接下来,我们可以添加一个索引计数器来启用从节点开始的链表子集的反转。
为了完成这项工作,新的尾节点(子列表的旧前端节点)需要链接到反向子节之后左侧的列表后面,否则我们将结束旧的头/新尾节点指向None
和砍掉尾巴。
class LinkedList:
# ...
def _reverse_from(self, start, length=-1):
curr = start
prev = None
while curr and length != 0:
nxt = curr.next
curr.next = prev
prev = curr
curr = nxt
length -= 1
if start:
# link the new tail (old head) with the back of the list
start.next = curr
return prev
最后,添加面向客户端的 function 分别反转每一半:
class LinkedList:
# ...
def reverse_halves(self):
length = len(self)
if length < 4:
return
mid_idx = length // 2
self.head = self._reverse_from(self.head, mid_idx)
if length % 2 == 0:
mid_idx -= 1
mid = self[mid_idx]
mid.next = self._reverse_from(mid.next)
将所有这些与示例运行放在一起,我们得到:
from functools import reduce
class Node:
def __init__(self, value, next_=None):
self.value = value
self.next = next_
def __repr__(self):
return str(self.value)
class LinkedList:
def __init__(self, els):
self.head = None
for e in reversed(els):
self.head = Node(e, self.head)
def _reverse_from(self, start, length=-1):
curr = start
prev = None
while curr and length != 0:
nxt = curr.next
curr.next = prev
prev = curr
curr = nxt
length -= 1
if start:
start.next = curr
return prev
def reverse(self):
self.head = self._reverse_from(self.head)
def reverse_halves(self):
length = len(self)
if length < 4:
return
mid_idx = length // 2
self.head = self._reverse_from(self.head, mid_idx)
if length % 2 == 0:
mid_idx -= 1
mid = self[mid_idx]
mid.next = self._reverse_from(mid.next)
def __iter__(self):
curr = self.head
while curr:
yield curr
curr = curr.next
def __getitem__(self, i):
try:
return list(zip(self, range(i + 1)))[-1][0]
except IndexError:
raise IndexError(i)
def __len__(self):
return reduce(lambda a, _: a + 1, self, 0)
def __repr__(self):
return "[" + "->".join([str(x) for x in self]) + "]"
if __name__ == "__main__":
for length in range(8):
ll = LinkedList(list(range(length)))
print("original:", ll)
ll.reverse_halves()
print("reversed:", ll, "\n")
Output:
original: []
reversed: []
original: [0]
reversed: [0]
original: [0->1]
reversed: [0->1]
original: [0->1->2]
reversed: [0->1->2]
original: [0->1->2->3]
reversed: [1->0->3->2]
original: [0->1->2->3->4]
reversed: [1->0->2->4->3]
original: [0->1->2->3->4->5]
reversed: [2->1->0->5->4->3]
original: [0->1->2->3->4->5->6]
reversed: [2->1->0->3->6->5->4]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.