这是对递归的滥用。如果链表的长度大于调用堆栈大小,则类无故中断。与迭代实现相比,它的编写效率和直观性也较低。
话虽如此,教授通常会要求以递归方式实现自然不适合递归的算法。一起玩,我会写一个处理实际递归的内部助手。这避免了可能使调用者感到困惑的尴尬默认参数,并使他们能够破坏函数的合同。
def add(self, val):
def add_recursively(curr, prev):
if curr:
add_recursively(curr.next, curr)
else:
if prev:
prev.next = Node(val)
else:
self.head = Node(val)
add_recursively(self.head, None)
最初尝试的主要问题是:
if current_node is None:
current_node = Node(val)
没有对链中前一个节点的引用,current_node 实际上并没有使用上述操作附加到任何东西,所以它只是在函数返回时被垃圾收集。
如果允许使用迭代,这是一种更自然的方法:
def add(self, val):
curr = self.head
prev = None
while curr:
prev, curr = curr, curr.next
if prev:
prev.next = Node(val)
else:
self.head = Node(val)
这是一个最小的完整用法示例:
class Node:
def __init__(self, val, next_node=None):
self.val = val
self.next = next_node
def __str__(self):
return str(self.val)
class LinkedList:
def __init__(self):
self.head = None
def add(self, val):
curr = self.head
prev = None
while curr:
prev, curr = curr, curr.next
if prev:
prev.next = Node(val)
else:
self.head = Node(val)
def __str__(self):
nodes = []
curr = self.head
while curr:
nodes.append(curr.val)
curr = curr.next
return "[" + " -> ".join(nodes) + "]"
if __name__ == "__main__":
llist = LinkedList()
llist.add("bananas")
llist.add("apples")
llist.add("cranberries")
print(llist) # => [bananas -> apples -> cranberries]
除此之外,考虑为您的 LinkedList 类保留一个 self.tail 节点引用。这将使添加操作 O(1) 而不是 O(n)。