Односвязный список со специальными методами в python, застрял

Односвязный список с двумя классами, Node и LinkedList, реализовать достаточно просто. однако моя проблема заключается в том, что речь идет об односвязном списке с доступом только к первому узлу (без сохраненной длины, без доступа к последнему узлу и без использования фиктивных узлов). Специальные методы, которые я не могу обдумать или найти в Интернете, похожи на встроенные в python операции со списками со сложностью O (1), например следующие:

aa = LinkedList()  --  creates empty list
aa.first()  --  similar to aa[0]
aa.rest()  --  similar to aa[1:]
aa.cons(item)  --  similar to aa[item:]
[item] + aa  --  similar to aa.insert(0, item)

Любое руководство, помощь, руководство будет принята с благодарностью. По какой-то причине я просто не могу интерпретировать встроенные операторы списка python в свои собственные методы в LinkedList без фиктивных узлов или сохраненной длины и итератора. Глядя на это, кажется, что я так близок, но ничего из того, что я делаю или нахожу, не помогает. Спасибо.

class Node:
  def __init__(self, data=None, next=None):
    self.data = data
    self.next = next

  def getData(self):
    return self.data

  def getNext(self):
    return self.next

  def setData(self, newdata):
    self.data = newdata

  def setNext(self, newnext):
    self.next = newnext

  def __str__(self):
    return str(self.data)

  def __repr__(self):
    return "Node(%s, %s)" % (repr(self.data), repr(self.next))

  def __eq__(self, other):
    return self.data == other.data and self.next == other.next

class myList:
  def __init__(self):
    self.first = Node()

  def add(self, data):
    newNode = Node() # create a new node
    newNode.data = data
    newNode.next = self.first # link the new node to the 'previous' node.
    self.first = newNode #  set the current node to the new one

  def first(self):
    return self.first.data


  def __repr__(self):
    plist = []
    for i in self:
        plist.append(i)
    return "LinkedList(%s)" % str(plist)

person DJXiej    schedule 17.04.2012    source источник
comment
Пожалуйста, опубликуйте свой текущий код, даже если он не полностью функционален.   -  person Andrew Clark    schedule 17.04.2012
comment
Как я уже сказал, я не знаю, что я делаю в этот момент, мне просто нужна зацепка. Но вот полный класс Node и базовый класс LinkedList   -  person DJXiej    schedule 17.04.2012
comment
Просто из любопытства, вы в классе, изучающем инкапсуляцию и объектно-ориентированное программирование? В Python немного странно делать что-то вроде node.setData(5), когда обычно можно сделать node.data = 5. Вы также можете использовать декораторы для переноса переменных, если вам нужно контролировать доступ к ним.   -  person Brent Writes Code    schedule 17.04.2012
comment
Почему бы не использовать collections.deque?   -  person yak    schedule 17.04.2012
comment
Это точно. Мы идем долгим путем, и все ресурсы, которые у нас есть, не очень помогают в этой маленькой программе. Просто застрял здесь и пытался найти этот маленький толчок   -  person DJXiej    schedule 17.04.2012
comment
Я думаю, что @sgusc нашел для вас самую важную проблему: у вас есть функция-метод с именем first и переменная-член с именем first. Одно скроет другое; переименовать один из них. Но, кстати, я рекомендую всегда объявлять ваши классы наследованием от object, чтобы у вас всегда была вся мощь наследования при написании программ на Python. например: class Node(object):   -  person steveha    schedule 17.04.2012
comment
Я думаю, что вы cons ошиблись. Он должен добавить item в начало списка, см. en.wikipedia.org/wiki/ Список_%28abstract_data_type%29   -  person agf    schedule 17.04.2012


Ответы (2)


Не видя вашего кода, я думаю, что основной совет, который я могу дать, заключается в том, что если вы выполняете операции на основе связанного списка, это потребует большого количества итераций. Использование таких вещей, как aa.cons(item), будет неэффективным и основано на итерации, потому что, в отличие от списка на основе массива, вы не можете перейти к элементу по определенному индексу.

Для следующих примеров я предполагаю, что ваш класс LinkedList имеет переменную с именем first, которая указывает на первый элемент в списке, и каждый Node имеет переменную с именем next, которая указывает на следующий элемент в списке, и переменную с именем data который содержит данные в этом узле.

Для aa.first() это должно быть легко, поскольку у вас уже есть переменная head, указывающая на первый элемент. Просто верни это.

Для других методов вам понадобится итерация. Это пример того, как вы можете просмотреть и распечатать список.

current = list.first
while current is not None:
    print current.data
    current = current.next

Для aa.rest() вам придется пропустить первый элемент, а затем просмотреть остальную часть списка. Чтобы сделать шаг в списке, вы, по сути, отслеживаете свое текущее местоположение и выполняете итерацию. Чтобы вернуть list[1:], мне кажется, проще всего создать новый список, а затем выполнить итерацию, добавляя все элементы с 1 до конца.

aa.rest() на самом деле всего лишь частный случай aa.cons(item). Вы перебираете список, пока ваш текущий указатель не достигнет item, а затем создаете новый список, содержащий все, что было после этого.

Вам не обязательно создавать новые списки для возврата из rest() и cons(...), это просто зависит от того, как вы хотите это реализовать. Я оставлю вставку для вас, чтобы подумать.

С LinkedList, который имеет только указатель на head, вы не получите O(1) ни за что, кроме добавления в начало списка или доступа к первому элементу, все остальное будет примерно O(N ).

Я надеюсь, что это поможет немного!

person Brent Writes Code    schedule 17.04.2012
comment
это кажется таким простым, но когда я пишу код, я получаю ошибки атрибутов и типов. Узел не вызывается при попытке вернуть aa.first() и т. д. - person DJXiej; 17.04.2012
comment
Мне понадобилась минута, чтобы заметить это. Я думаю, ваша проблема в том, что у вас есть переменная с именем first и метод с именем first() в файле LinkedList. Попробуйте назвать метод по-другому. Проблема в том, что сначала создается метод first, затем вы перезаписываете его переменной first в __init__, поэтому, когда вы переходите к aa.first(), он пытается вызвать первый узел в списке как метод. - person Brent Writes Code; 17.04.2012
comment
@user1337598 user1337598, я не уверен, что вы имеете в виду под Node, который нельзя вызывать. Когда вы вызываете Node(), Python создает для вас новый экземпляр. Это не то, что вам нужно для aa.first(), поэтому я не уверен, почему вы упомянули об этом. - person steveha; 17.04.2012

@sgusc обнаружил одну действительно большую проблему с тем, что у вас есть: назвать функцию first и назвать атрибут данных first. Последнее переопределяет первое (поскольку функция фактически находится в class, а не в экземпляре).

Исправление этого дает что-то, что близко к работе. Я упростил несколько вещей, добавил небольшой тестовый драйвер и добавил __iter__, который использует генератор для получения данных каждого узла по очереди, так что for i in selfmyList.__repr__) может работать. Разница:

--- a/user1337598.py
+++ b/user1337598.py
@@ -1,4 +1,4 @@
-class Node:
+class Node(object):
   def __init__(self, data=None, next=None):
     self.data = data
     self.next = next
@@ -19,27 +19,36 @@ class Node:
     return str(self.data)

   def __repr__(self):
-    return "Node(%s, %s)" % (repr(self.data), repr(self.next))
+    return "Node(%r, %r)" % (self.data, self.next)

   def __eq__(self, other):
     return self.data == other.data and self.next == other.next

-class myList:
+class myList(object):
   def __init__(self):
-    self.first = Node()
+    self.first = None

   def add(self, data):
-    newNode = Node() # create a new node
-    newNode.data = data
-    newNode.next = self.first # link the new node to the 'previous' node.
+    newNode = Node(data, self.first) # create a new node
     self.first = newNode #  set the current node to the new one

-  def first(self):
+  def getFirst(self):
     return self.first.data

+  def __iter__(self):
+      node = self.first
+      while node is not None:
+          yield node.data
+          node = node.next

   def __repr__(self):
     plist = []
     for i in self:
         plist.append(i)
     return "LinkedList(%s)" % str(plist)
+
+if __name__ == '__main__':
+    lst = myList()
+    lst.add(1)
+    lst.add(2)
+    print repr(lst)

Обратите внимание, что repr использует имя LinkedList, несмотря на то, что имя класса myList. Обычно я пишу свои функции repr для использования self.__class__.__name__, например:

def __repr__(self):
    return '%s(%r, %r)' % (self.__class__.__name__, self.item1, self.item2)

что также позволяет базовому классу __repr__ работать с производными классами (иногда с небольшой помощью производного класса).

person torek    schedule 17.04.2012