Это не столько проблема кодирования, сколько концептуальная проблема. Вам нужно выяснить, как вы хотите, чтобы ваш код вел себя. Реализация желаемого поведения не является (в данном случае) сложным.
Скажем, мы хотим, чтобы эти модели поведения:
# construction
dlist = DoublyLinkedList()
# access to head and tail nodes
dlist.head # should return the head node
dlist.tail # should return the tail node
dlist.head.prev is None # should be True
dlist.tail.next is None # should be True
# adding nodes at both ends
dlist.add_head()
dlist.add_tail()
# iteration in both directions
for node in dlist:
# do something to the node
for node in reversed(dlist):
# do something to the node
Когда вы выписали желаемое поведение, как это, вы также получили некоторые тестовый код готов.
Теперь давайте начнем с изменения Node
класса (you should use CamelCase for class names):
class Node:
def __init__(self, data=None, prev=None, next=None):
self.data = data
self.prev = prev
self.next = next
def __repr__(self):
return '<{}, {}>'.format(self.data, self.next)
Добавим prev
, так что, очевидно, необходимо. Но мы также улучшаем исходную версию, имея data
и next
в качестве параметров, поэтому вы можете установить эти значения при создании узла. И __repr__
всегда приятно иметь, для отладки, если не для чего-либо еще.
Теперь для самого списка. Ключ: (a) вместо одного cur_node
, вам нужно два ручек в списке, который я вызывал head
и tail
, и (b) при добавлении узлов самый первый узел является частным случаем, когда мы должны вносить изменения как в head
, так и в tail
.
class DoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
def __repr__(self):
return '<DoublyLinkedList {}>'.format(self.head)
def add_head(self, data=None):
if self.head is None:
self.head = self.tail = Node(data) # the very fist node
else:
new_head = Node(data=data, next=self.head) # prev is None
self.head.prev = self.head = new_head
def add_tail(self, data=None):
if self.tail is None:
self.head = self.tail = Node(data) # the very first node
else:
new_tail = Node(data=data, prev=self.tail) # next is None
self.tail.next = self.tail = new_tail
# implements iteration from head to tail
def __iter__(self):
current = self.head
while current is not None:
yield current
current= current.next
# implements iteration from tail to head
def __reversed__(self):
current = self.tail
while current is not None:
yield current
current = current.prev
Давайте проверим это
>>> dlist = DoublyLinkedList()
>>> print(dlist)
<DoublyLinkedList None>
>>> dlist.add_head(1)
>>> dlist.add_tail(2)
>>> dlist.add_tail(3)
>>> dlist.add_head(0)
>>> print(dlist) # __repr__ is such a nice thing to have
<DoublyLinkedList <0, <1, <2, <3, None>>>>>
>>> print(dlist.head)
<0, <1, <2, <3, None>>>>
>>> print(dlist.tail)
<3, None>
>>> print(dlist.head.prev is None, dlist.tail.next is None)
True, True
>>> print(dlist.tail.prev.next is dlist.tail)
True
>>> [node.data for node in dlist]
[0, 1, 2, 3]
>>> for node in reversed(dlist):
... print(node.data, node)
3 <3, None>
2 <2, <3, None>>
1 <1, <2, <3, None>>>
0 <0, <1, <2, <3, None>>>>
Есть ли причина, что вы не используете [ 'collections.deque'] (https://docs.python.org/3/library/collections.html # collections.deque)? – Kevin
Да, я знаю, что могу легко реализовать эту функциональность, но я пытаюсь узнать, как работают базовые структуры данных. – 123
В настоящее время ваш связанный «add_node» добавляет узел в «начало» списка, а не «конец» ... это то, что вы намеревались? – donkopotamus