我现在正在处理一个双向链接列表类,我的下一个和它的方法遇到了麻烦。这是我已经上交的课程项目,现在只是想了解如何实际修复它以使其有用。
我想让我的代码做的是设置一个当前指针,从标题开始,然后继续前进直到指示终止或它到达预告片。我想访问存储在每个节点的值。节点类是主链表类的子类。这是我的代码。当我调用我的方法(发布我的追加方法)时出现我的问题;无法识别当前指针。关于如何解决这个问题的任何想法?
class Linked_List:
class __Node:
def __init__(self, val):
self.val = val
self.size = 0
def __init__(self):
self.header = Linked_List.__Node('header')
self.trailer = Linked_List.__Node('trailer')
self.header.next = self.trailer
self.trailer.prev = self.header
self.size = 0
self.current = self.header
self.current.next = self.trailer
def __iter__(self):
self.current = self.header
return self
def __next__(self):
if self.current == self.trailer:
raise StopIteration
result = self.Linked_List.__Node[self.current]
self.current = self.current.next
return result
def append(self, val):
new_node = Linked_List.__Node(val)
if self.header.next is self.trailer:
self.header.next = new_node
self.trailer.prev = new_node
self.current = self.header
else:
while self.current is not self.trailer:
self.current = self.current.next
self.current.next = new_node
new_node.next = self.trailer
new_node.prev = self.current
self.size += 1
我是python的新手(以及一般的编码)所以任何建议都会很棒。
答案 0 :(得分:2)
您的代码有多个问题,在您尝试使用时会显现出来。让我们假设以下代码来测试它:
l = Linked_List()
l.append('foo')
l.append('bar')
l.append('baz')
print([x.val for x in l])
AttributeError:' __ Node'对象没有属性' next'
第一期:您的__Node
类型没有next
和prev
的字段:
class __Node:
def __init__(self, val):
self.val = val
self.size = 0
self.prev = None
self.next = None
AttributeError:' NoneType'对象没有属性' next'
第二个问题:并非总是为附加节点填充next
。在append
中的一个路径中,您未设置新节点的next
和prev
:
def append(self, val):
new_node = Linked_List.__Node(val)
if self.header.next is self.trailer:
# set the attributes on new_node
new_node.prev = self.header
new_node.next = self.trailer
self.header.next = new_node
self.trailer.prev = new_node
self.current = self.header
# …
AttributeError:' Linked_List'对象没有属性' Linked_List'
第三个问题:不知道你在__next__
那里想做什么。您只需访问self.current
那里:
def __next__(self):
if self.current == self.trailer:
raise StopIteration
result = self.current
self.current = self.current.next
return result
一旦我们修复了所有这些,我们就有了一个成功运行的代码。但我们只得到以下输出:['header', 'foo']
。当然,这不是我们想要的。
发生这种情况的原因是因为物品的实际顺序如下:
header
foo
trailer
baz
trailer
(是的,有一个递归)显然,append
毕竟不能正常工作。如果您只是附加两个元素,则可以看到在尾部元素之后添加了元素。这意味着self.current
确实会在追加循环中点击尾部元素:
while self.current is not self.trailer:
self.current = self.current.next
如果你仔细观察,就会发生这种情况:首先更新self.current
,然后进行检查以最终取消循环。那时self.current
是self.trailer
。所以我们应该检查self.current.next
:
while self.current.next is not self.trailer:
self.current = self.current.next
修复后,我们得到以下输出:['header', 'foo', 'bar', 'baz']
。这几乎是我们想要看到的。我们现在需要做的就是跳过header元素。我们只需从标题后的元素开始:
def __iter__(self):
self.current = self.header.next
return self
然后它有效。
这就是让代码运行所需的一切。 但是,我通常会建议不要采用这种做法。您正在列表中存储迭代状态,这非常脆弱。您应该尽可能将此状态设置为本地状态。
特别是,链接列表不需要是可枚举和枚举器。前者实现__iter__
,后者实施__next__
。可枚举的意思是“你可以迭代这个东西”,而枚举器是执行迭代并具有迭代状态的东西。
尝试移动迭代状态 off 链接列表,使其只能枚举而不是枚举器。为此,请添加LinkedListEnumerator
类型,该类型具有对列表的引用并跟踪当前元素:
class LinkedListEnumerator:
def __init__ (self, lst):
self.lst = lst
self.current = lst.header.next
def __iter__ (self):
return self
def __next__ (self):
if self.current == self.lst.trailer:
raise StopIteration
result = self.current
self.current = self.current.next
return result
然后,您可以删除链接列表中的__next__
方法,并使用以下内容替换__iter__
方法:
def __iter__(self):
return LinkedListEnumerator(self)
然后你不再拥有链表中的状态。 (此时,您还应该在current
中append
一个本地变量并完全摆脱self.current