我试图用以下函数实现双向链表:
_insertItemAfterNode(self,index)
_nodeBeforeIndex(self, index)
insertItemAtTheFront(self,item)
insertItemAtTheEnd(self,item)
insertItemAtIndex(self, index, item)
最后三个函数应该使用前两个私有方法。 这是我到目前为止,但我似乎无法工作。任何帮助表示赞赏!!!
# DoublyLinkedLists
class Node(object):
def __init__(self, prev = None, data=None, next = None):
self._prev = prev
self._data = data
self._next = next
def __str__(self):
return str(self._data)
def __repr__(self):
return "Node(%s,%s,%s)" % (repr(self._prev), repr(self._data), repr (self._next))
def __eq__(self, other):
if other == None:
return False
else:
return self._prev == other._prev and self._data == other._data and self._next == other._next`enter code here`
class DoublyLinkedList(object):
def __init__(self):
self._first = Node(None, None, None)
self._length = 0
self._last = Node(None, None, None)
def __len__(self):
return self._length
def _insertItemAfterNode(self,item,aNode):
newNode = Node(aNode._prev, item, aNode._next)
aNode._next= newNode._prev
aNode._prev=newNode._next
self._length += 1
def _nodeBeforeIndex(self, index):
if 0 <= index <= self._length:
aNode = self._first
for i in range(index):
aNode = aNode._next
return aNode
else:
raise IndexError
def _nodeAfterIndex(self, index):
if 0<= index <= self.length:
aNode = self._last
for i in range(index):
aNode = aNode._prev
return aNode
else:
raise IndexError
def __getitem__(self, index):
return self._nodeBeforeIndex(index)._next._data
def insertAtEnd(self, item):
self._nodeAfterIndex(item)
def __iter__(self):
return DoublyLinkedListIterator(self)
def __setitem__(self, index, item):
self._nodeBeforeIndex(index)._next._data = item
def insertItemAtTheFront(self, item):
self._insertItemAfterNode(item, self._nodeBeforeIndex(0))
def insertItemAtTheEnd(self, item):
self._insertItemAfterNode(item, self._nodeBeforeIndex(self._length))
def insertItemAtIndex(self, index, item):
'''Valid range 0 <= index <= length.'''
self._insertItemAfterNode(item, self._nodeBeforeIndex(index))
def __iter__(self):
return DoublyLinkedListIterator(self)
def __repr__(self):
#used by print in abscence of __str__ .
plist = []
for item in self:
plist.append(item)
return "DoublyLinkedList(%s)" % str(plist)
class DoublyLinkedListIterator(object):
def __init__(self, aList):
self._list = aList
self._currentIndex = -1
self._currentNode = self._list._first
def __iter__(self):
return self
def __next__(self):
if self._currentIndex == self._list._length - 1:
raise StopIteration
else:
self._currentIndex += 1
self._currentNode = self._currentNode._next
return self._currentNode._data
def main():
x = DoublyLinkedList()
x.insertItemAtTheEnd(45)
print(x)
main()
答案 0 :(得分:1)
您的代码有些奇怪。让我们深入研究我发现的第一个问题:
def _insertItemAfterNode(self,item,aNode):
newNode = Node(aNode._prev, item, aNode._next)
aNode._next= newNode._prev
aNode._prev=newNode._next
self._length += 1
假设你有:
prevNode <-> aNode <-> nextNode
您现在创建一个newNode
,其前一个指向prevNode
,后续指向nextNode
。然后你反转aNode
的指针。 prevNode
仍然认为其后续节点为aNode
,但aNode
现在认为其后续节点为prevNode
。
/---------\
/----> aNode < v
prevNode <--------/ \-- nextNode
^ ^
\---- newNode --/
这几乎不是你想要的:
prevNode <-> aNode <-> newNode <-> nextNode
这是一个更好的版本:
def _insertItemAfterNode(self,item,aNode):
# If the new Node follows aNode, than its preceeding node is aNode,
# not aNode._prev!
newNode = Node(aNode, item, aNode._next)
# Now we need to make aNode point at its new following Node, newNode
aNode._next = newNode
# And finally, we need to make the following Node notice that
# its preceeding Node has changed.
newNode._next._prev = newNode
self._length += 1
这并不关心任何边缘情况,例如,如果aNode
是链表中的最后一个节点,该怎么办。
我建议你拿出一张纸,画出你需要为每个操作改变不同链接的方式,因为很难把这一切都记在脑后。
确保查看所有边缘情况,即。放入一个空列表,将项目放入第一个和最后一个位置。
最后,在改变链接时,总是仔细检查每个链接指向每条指令的位置,而不是意外丢弃任何节点。
答案 1 :(得分:1)
我发现您的代码存在两个直接问题。可能还有更多我没有注意到的问题,但这些问题可能会阻止您在修复之前看到任何其他问题。
第一个问题非常简单。您的_first
课程中有两个前哨节点_last
和DoublyLinkedList
。但是,它们没有相互关联,所以当稍后添加更多节点时,它们将不会像它们应该那样连接到两个标记。
您可以通过更改__init__
方法来解决此问题:
def __init__(self):
self._first = Node(None, None, None)
self._length = 0
self._last = Node(self._first, None, None) # pass first node as an arg here
self._first._next = self._last # make a link back too
第二个问题是你如何添加节点。有几个地方您要从节点的_prev
或_next
属性中分配值,而不是引用节点本身。
让我们想一下包含A
和C
个节点的列表,并希望在它们之间插入B
。您需要将B
的节点链接到A
和C
,然后修改C
和A
以链接回来。在您的代码中,A
为aNode
,B
为newNode
,C
为(开始时)aNode._next
。
def _insertItemAfterNode(self, item, aNode):
newNode = Node(aNode, item, aNode._next) # link B to A and C
aNode._next._prev = newNode # link C back to B
aNode._next = newNode # and A to B too!
self._length += 1