[英]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.