Связанные списки и рекурсия в python
Я новичок в программировании и начинаю в Python. Мой вопрос касается связанных списков, я написал класс для связанного списка, что мне нужно сделать, это иметь функцию с входом в качестве ссылки, указывающей на начало списка. - linked_list.head ' как я понимаю, с linked_list является именем списка, о котором идет речь. В частности, используя рекурсию, я пытаюсь найти длину списка в качестве вывода этой функции. Вот мой код, я не совсем понимаю, как я можно было бы перейти к следующему узлу и вернуть число узлов с рекурсией в этом случае.
import re
def special_match(strg, search=re.compile(r'[^A-Za-z.]').search):
return not bool(search(strg))
class node:
def __init__(self, data, next):
self.data = data
self.next = next
def get_data(self):
return self.data
def set_data(self,value):
self.data = value
def get_next_node(self):
return self.next
def set_next_node(self,val):
self.next = val
class linked_list:
def __init__(self):
self.head = None
self.tail = None
self.size = 0
def add_first(self,e):
newest = node(e,None)
newest.next = self.head
self.head = newest
self.size = self.size+1
if self.size == 1:
self.tail = newest
def add_last(self,e):
newest = node(e,None)
if self.size > 0:
self.tail.next = newest
else:
self.head = newest
self.tail = newest
self.size = self.size+1
def remove_first(self):
if self.size == 0:
print('The linked list is empty')
elif self.size == 1:
answer = self.head.data
self.head = None
self.tail = None
self.size -= 1
return answer
else:
answer = self.head.data
self.head = self.head.next
self.size = self.size - 1
return answer
def remove_last(self):
if self.size == 0:
print('The linked list is empty')
elif self.size == 1:
answer = self.tail.data
self.head = None
self.tail = None
self.size -= 1
return answer
else:
temp = self.head
while(temp.next is not None):
temp = temp.next
temp.next = None
def node_number(self,reference):
reference = str(reference)
count = 0
temp = self.head
if special_match(reference) == True:
count =+ 1
temp = temp.next
return self.node_number
else:
print('You have made wrong input')
def printe(self):
curr = self.head
while curr:
print(curr.data)
curr = curr.get_next_node()
if self.size == 0:
print('The list is empty')
3 ответа:
Рекурсия-это функциональное наследие, и поэтому использование ее с функциональным стилем даст наилучшие результаты. В вашей программе реализован связанный список с использованием императивного стиляизменяемых узлов - то есть значения
data
иnext
могут изменяться с течением времени. Хотя это может показаться интуитивным подходом, я хотел бы сосредоточиться на неизменяемой реализации, которая освобождает нас от калечащей сложности состояния. В этом ответе мы реализуем Весь связанный список функции, использующие рекурсивные формы, выраженные функциональными стилями.Мы начнем с простой
node
иlinked_list
классов. На этот раз мы пропустим созданиеget_*
иset_*
функций, как вы это сделали. Есть и другие способы сделать это в Python, как мы увидим через минутуclass node: def __init__ (self, left, right): self.left = left self.right = right class linked_list: def __init__ (self, node = None): self.node = node
Далее мы определяем примитивные свойства для нашего списка:
is_empty
,head
, иtail
class linked_list: def __init__ (self, node = None): self.node = node @property def is_empty (self): return self.node is None @property def head (self): if self.is_empty: raise Exception ("cannot get head of an empty list") else: return self.node.left @property def tail (self): if self.is_empty: raise Exception ("cannot get tail of an empty list") else: return self.node.right
Теперь использование
node
полностью абстрагировано, и мы можем написать список более высокого уровня поведение с помощью наших новых свойствВыше мы видим, что очень легко говорить о нашем списке через использование его свойств. Прежде чем мы пойдем дальше, давайте посмотрим, как мы можем построить списки и визуализировать их с помощьюclass linked_list: ... def length (self): if self.is_empty: return 0 else: return 1 + self.tail.length ()
__str__
class linked_list: ... def add_first (self, x): return linked_list (node (x, self)) def __str__ (self): if self.is_empty: return "None" else: return str (self.head) + " -> " + str (self.tail) ls = linked_list().add_first(3).add_first(2).add_first(1) print (ls) # 1 -> 2 -> 3 -> None print (ls.length ()) # 3
Помните, поскольку мы построили неизменяемый связанный список,
add_first
не изменяет список, который был вызванls = linked_list().add_first(3).add_first(2).add_first(1) print (ls) # 1 -> 2 -> 3 -> None print (ls.add_first (0)) # 0 -> 1 -> 2 -> 3 -> None print (ls) # 1 -> 2 -> 3 -> None
Прежде чем мы двинемся дальше, давайте сделаем это проще. постройте наши связанные списки. Мы добавляем статический
build
функция, которая позволяет нам построить список из переменного числа входовТеперь давайте посмотрим на ваши функцииclass linked_list: ... @staticmethod def build (x = None, *rest): if x is None: return linked_list () else: return linked_list (node (x, linked_list.build (*rest))) print (linked_list.build (1,2,3)) # 1 -> 2 -> 3 -> None
remove_first
иremove_last
теперьclass linked_list: ... def remove_first (self): if self.is_empty: raise Exception ("cannot remove first element of an empty list") else: return self.tail def remove_last (self): if self.is_empty: raise Exception ("cannot remove last element of an empty list") elif self.tail.is_empty: return self.tail else: return linked_list (node (self.head, self.tail.remove_last ())) ls = linked_list.build (1,2,3) print (ls) # 1 -> 2 -> 3 -> None print (ls.remove_first ()) # 2 -> 3 -> None print (ls.remove_last ()) # 1 -> 2 -> None print (ls) # 1 -> 2 -> 3 -> None
И
node_number
class linked_list: ... def node_number (self, index = 0): if self.is_empty: raise Exception ("index out of bounds") elif index is 0: return self.head else: return self.tail.node_number (index - 1) ls = linked_list.build ("a", "b", "c") print (ls.node_number (0)) # "a" print (ls.node_number (1)) # "b" print (ls.node_number (10)) # Exception: index out of bounds
И A
add_last
халяваclass linked_list: ... def add_last (self, x): if self.is_empty: return self.add_first (x) else: return linked_list (node (self.head, self.tail.add_last (x))) ls = linked_list.build (1, 2, 3) print (ls) # 1 -> 2 -> 3 -> None print (ls.add_last (4)) # 1 -> 2 -> 3 -> 4 -> None print (ls) # 1 -> 2 -> 3 -> None
Демонстрация полной программы на repl.it
Я бы установил его там, где функция длины на самом деле является частью класса
Node
, а не КлассаLinked_List
. КлассLinked_List
также будет иметь функциюlength
, но все, что он будет делать, - это вызывать функциюlength
узлаhead
списка.Тогда каждый узел просто вернет
length
своего экземпляраnext
плюс 1.
Рекурсия должна иметь базовый случай, в котором код проверяет, является ли атрибут
next
None
. Если да, то функция возвращает текущий счетчик. Если нет, счетчик увеличивается и функцияlength
вызывается как метод атрибутаnext
, чтобы иметь возможность продолжить прогрессию рекурсии по ссылкам, которые могут быть записаны как:|val1|pointer| -> |val2|pointer| -> |val3|pointer| -> |val4|pointer| -> |val5|None|
Во-первых, Ниже приведена более простая конструкция класса связанного списка для демонстрации:
class Node: def __init__(self, val=None): self.head = val self.next = None def length(self, count = 0): if self.next is None: return count + 1 if self.next is None and self.head else count return self.next.length(count + 1) def insert(self, v): if self.head is None: self.head = v else: if self.next is None: self.next = Node(v) else: self.next.insert(v) @classmethod def regular_transform(cls, node, nodes = []): '''for easier visulization''' return nodes+[node.head] if not node.next else cls.regular_transform(node.next, nodes+[node.head]) n = Node() for i in [56, 232, 424, 2, 11]: n.insert(i) print(Node.regular_transform(n)) print(n.length())
Вывод:
[56, 232, 424, 2, 11] 5