我正在研究Python 3.11中的链表。我编写了书中给出的代码。代码如下:
class Node:
def __init__(self, data, next=None):
self.data = data
self.next = next
class LinkedList:
def __init__(self):
self.head = None
def __str__(self):
node = self.head
while node is not None:
print(node.data)
node = node.next
def append(self, data):
if not self.head:
self.head = Node(data)
return
current = self.head
while current.next:
current = current.next
current.next = Node(data)
def search(self, target):
current = self.head
while current.next:
if current.data == target:
return True
else:
current = current.next
return False
def remove(self, target):
if self.head == target:
self.head = self.head.next
return
current = self.head
previous = None
while current:
if current.data == target:
previous.next = current.next
previous = current
current = current.next
def reverse_list(self):
current = self.head
previous = None
while current:
next = current.next
current.next = previous
previous = current
current = next
self.head = previous
a_list = LinkedList()
a_list.append("Tuesday")
a_list.append("Wednesday")
print(a_list)
import random
a_list = LinkedList()
for i in range(0, 20):
j = random.randint(1, 30)
a_list.search(j)
print(j, end=' ')
当我运行此代码时,出现错误:
回溯(最近一次调用最后一次): 文件 linked_list.py,第 62 行,位于 打印(a_列表) 类型错误:str返回非字符串(类型为NoneType)
由于函数str出现问题,我尝试了以下操作(最后添加 return ): 1)
def __str__(self):
node = self.head
while node is not None:
print(node.data)
node = node.next
return node
结果是一样的:
回溯(最近一次调用最后一次): 文件 linked_list.py,第 62 行,位于 打印(a_列表) 类型错误:str返回非字符串(类型为NoneType)
2)
def __str__(self):
node = self.head
while node is not None:
print(node.data)
node = node.next
return node.data
结果:
回溯(最近一次调用最后一次): 文件“linked_list.py”,第 63 行,位于 打印(a_列表) 文件“linked_list.py”,第 18 行,位于 str 中 返回节点数据 AttributeError:“NoneType”对象没有属性“data”
您的代码中存在多个问题:
你问的问题:
__str__
的作者错误地认为应该打印列表的内容。这不是__str__
的目的。相反,它应该返回列表的字符串版本。调用者可以对该字符串执行某些操作,可以打印它或执行其他操作。
一个快速修复方法是将
print
调用替换为将数据连接成字符串然后返回它的代码:
def __str__(self):
s = ""
node = self.head
while node is not None:
s += f"{node.data} " # don't print, but collect in a string
node = node.next
return s
但这并不是最优雅的方式。您可以从首先定义
__iter__
中受益,这对于其他目的也很有用......
search
具有检查 current.next
但不确保 current
不是 None
的条件。因此,当列表为空时,此代码将遇到错误。其次,当最后一个节点(仅)具有搜索到的数据时,它不会找到匹配项。条件应该是current
,而不是current.next
remove
将 head
与 target
进行比较,也将 current.data
与 target
进行比较。这是不一致的。该函数可以使用节点实例或数据来调用。现在你有了一个混合。我想您希望使用 data来调用
remove
,因此第一个 if
语句是错误的。你应该先检查链表是否有节点,然后检查头节点的数据。
remove
在删除节点后继续循环,尝试找到更多匹配项。这很好,但它与处理头节点中的匹配的方式不一致,因为当存在匹配时,您将退出该函数。为了保持一致,您不应该退出那里,并继续前进(检查头部,然后检查其余节点)。
当
remove
在循环中找到匹配项时,会将previous
更新为已删除的节点。这是不正确的。在这种情况下,previous
应保持不变并引用现在已删除节点之前的节点。
不是问题,但是:
a_list.search(j)
但不对返回值执行任何操作,因此它是无用的。search
方法进行一些正向和负向测试。search
并未表明它返回布尔值(而不是节点或位置)。称之为 has
或 includes
或 contains
。或者更好的是,定义 __contains__
,这样您就可以使用 in
运算符来代替。_list
中不需要添加reverse_list
。这是链表上的方法,因此很明显,反转涉及(链表)。这里是
LinkedList
类的建议代码:
class LinkedList:
def __init__(self):
self.head = None
def __iter__(self): # Make linked list iterable
node = self.head
while node:
yield node.data
node = node.next
def __str__(self): # Don't print, but return str
# Make use of __iter__
return " ".join(map(str, self))
def append(self, data):
if not self.head:
self.head = Node(data)
return
current = self.head
while current.next:
current = current.next
current.next = Node(data)
def __contains__(self, target): # Support IN operator
current = self.head
while current: # fixed condition
if current.data == target:
return True
current = current.next # No need for ELSE
return False
def remove(self, target):
# Check in a loop, and don't return:
while self.head and self.head.data == target: # compare data, not node
self.head = self.head.next
current = self.head
previous = None
while current:
if current.data == target:
previous.next = current.next
else: # Only update previous when there is no match
previous = current
current = current.next
def reverse(self): # Better name
current = self.head
previous = None
while current:
next = current.next
current.next = previous
previous = current
current = next
self.head = previous