Python __双链接哨兵列表中的next和iter方法
我现在正在研究一个双链表类,我的next和iter方法遇到了麻烦。这是为我的班级准备的一个项目,我已经上交了,现在只想了解如何实际修复它,使它变得有用 我想让我的代码做的是设置一个当前指针,从标题开始,然后继续前进,直到指示终止或到达尾部。我想访问存储在每个节点上的值。节点类是主链表类的子类。这是我的密码。当我调用我的方法(发布我的append方法)时,我的问题出现了;无法识别当前指针。有没有办法解决这个问题Python __双链接哨兵列表中的next和iter方法,python,python-3.x,doubly-linked-list,Python,Python 3.x,Doubly Linked List,我现在正在研究一个双链表类,我的next和iter方法遇到了麻烦。这是为我的班级准备的一个项目,我已经上交了,现在只想了解如何实际修复它,使它变得有用 我想让我的代码做的是设置一个当前指针,从标题开始,然后继续前进,直到指示终止或到达尾部。我想访问存储在每个节点上的值。节点类是主链表类的子类。这是我的密码。当我调用我的方法(发布我的append方法)时,我的问题出现了;无法识别当前指针。有没有办法解决这个问题 class Linked_List: class __Node:
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(以及一般的编码)比较新,所以任何建议都会令人惊讶。您的代码有多个问题,当您尝试使用它时,这些问题会变得很明显。让我们假设以下代码来测试它:
l = Linked_List()
l.append('foo')
l.append('bar')
l.append('baz')
print([x.val for x in l])
AttributeError:“\uu节点”对象没有属性“next” 第一个问题:您的
\u节点
类型没有用于下一个
和上一个
的字段:
class __Node:
def __init__(self, val):
self.val = val
self.size = 0
self.prev = None
self.next = None
AttributeError:“非类型”对象没有属性“下一个”
第二个问题: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:“链接列表”对象没有属性“链接列表”
第三个问题:不知道你在\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。您只需在那里访问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
def __iter__(self):
return LinkedListEnumerator(self)
(是的,有一个递归)显然,append
毕竟不能正常工作。如果您只是附加了两个元素,您可以看到该元素被添加到拖车元素之后。这意味着,self.current
确实命中了append循环中的拖车元素:
while self.current is not self.trailer:
self.current = self.current.next
如果你看一下,这是有道理的:self.current
首先更新,然后进行检查以最终取消循环。当时self.current
是self.trail
。因此,我们应该检查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
然后它就起作用了
这就是让代码运行所需要的全部然而,我通常建议不要使用这种方法。您正在列表中存储迭代状态,这是非常脆弱的。你应该尽可能地让这个州成为当地人
特别是,链表不需要既是可枚举的又是枚举器。实现\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
实现前者,实现实现后者。Enumerable表示“您可以迭代这个东西”,而枚举器是执行迭代的东西,并且具有迭代状态
尝试将迭代状态从链表中移出,使其仅可枚举,而不是枚举器。为此,请添加一个引用列表并跟踪当前元素的LinkedListNumerator
类型:
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
然后,您可以删除链接列表中的\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
方法,并用以下方法替换\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
header
foo
trailer
baz
trailer
def __iter__(self):
return LinkedListEnumerator(self)
然后你就不再有链接列表中的状态了。(此时,您还应该在append
中将current
设置为局部变量,并完全删除self.current
)那么,您是否在没有任何值的情况下初始化了链接列表?似乎即使没有任何值,它的大小也是2。这就是您想要的吗?另外,您通常希望节点存储关于下一个和上一个节点的状态。链表用于添加/删除和遍历。它不必担心节点之间的关系。@Coldspeed头部和尾部是这里的一个实现细节。那太好了。此外,我看不出列表在哪里担心节点之间的关系。修改列表时,必须重新链接某些元素。我认为OP的一般方法没有任何错误。@poke我假设“链表”意味着节点类具有self.next和self.prev。嗯,我需要更深入地看看这个…:-)@是的,没错。这就是OP的代码存在的问题之一:PWow!非常感谢你!我认为我的很多问题都源于对我的问题从哪里开始的缺乏了解。另外,我真的很感激你解释为什么我采取的方法不是最佳的;我得到的最好的解释!