173 lines
6.4 KiB
Python
173 lines
6.4 KiB
Python
"""
|
||
https://stepik.org/lesson/701988/step/7?unit=702089
|
||
|
||
Объявите класс LinkedList (связный список) для работы со следующей структурой данных:
|
||
|
||
Здесь создается список из связанных между собой объектов класса ObjList. Объекты этого класса создаются командой:
|
||
|
||
obj = ObjList(data)
|
||
где data - строка с некоторой информацией. Также в каждом объекте obj класса ObjList должны создаваться следующие локальные атрибуты:
|
||
|
||
__data - ссылка на строку с данными;
|
||
__prev - ссылка на предыдущий объект связного списка (если объекта нет, то __prev = None);
|
||
__next - ссылка на следующий объект связного списка (если объекта нет, то __next = None).
|
||
|
||
В свою очередь, объекты класса LinkedList должны создаваться командой:
|
||
|
||
linked_lst = LinkedList()
|
||
и содержать локальные атрибуты:
|
||
|
||
head - ссылка на первый объект связного списка (если список пуст, то head = None);
|
||
tail - ссылка на последний объект связного списка (если список пуст, то tail = None).
|
||
|
||
А сам класс содержать следующие методы:
|
||
|
||
add_obj(obj) - добавление нового объекта obj класса ObjList в конец связного списка;
|
||
remove_obj(indx) - удаление объекта класса ObjList из связного списка по его порядковому номеру (индексу); индекс отсчитывается с нуля.
|
||
|
||
Также с объектами класса LinkedList должны поддерживаться следующие операции:
|
||
|
||
len(linked_lst) - возвращает число объектов в связном списке;
|
||
linked_lst(indx) - возвращает строку __data, хранящуюся в объекте класса ObjList, расположенного под индексом indx (в связном списке).
|
||
|
||
Пример использования классов (эти строчки в программе писать не нужно):
|
||
|
||
linked_lst = LinkedList()
|
||
linked_lst.add_obj(ObjList("Sergey"))
|
||
linked_lst.add_obj(ObjList("Balakirev"))
|
||
linked_lst.add_obj(ObjList("Python"))
|
||
linked_lst.remove_obj(2)
|
||
linked_lst.add_obj(ObjList("Python ООП"))
|
||
n = len(linked_lst) # n = 3
|
||
s = linked_lst(1) # s = Balakirev
|
||
P.S. На экран в программе ничего выводить не нужно.
|
||
"""
|
||
|
||
|
||
class LinkedList:
|
||
def __init__(self):
|
||
self.head = None
|
||
self.tail = None
|
||
|
||
def add_obj(self, obj):
|
||
if not self.head:
|
||
self.head = obj
|
||
self.tail = obj
|
||
else:
|
||
self.tail.next = obj
|
||
obj.prev = self.tail
|
||
self.tail = obj
|
||
|
||
def __iter__(self):
|
||
obj = self.head
|
||
while obj and obj != self.tail.next:
|
||
yield obj
|
||
obj = obj.next
|
||
|
||
def __reversed__(self):
|
||
obj = self.tail
|
||
while obj and obj != self.head.prev:
|
||
yield obj
|
||
obj = obj.prev
|
||
|
||
def remove_obj(self, idx):
|
||
if not self:
|
||
pass
|
||
elif idx == 0:
|
||
self.head = self.head.next
|
||
if self.head:
|
||
self.head.prev = None
|
||
elif idx == len(self) - 1:
|
||
self.tail = self.tail.prev
|
||
self.tail.next = None
|
||
else:
|
||
obj = self.head
|
||
for _ in range(idx):
|
||
obj = obj.next
|
||
obj.prev.next = obj.next
|
||
obj.next.prev = obj.prev
|
||
|
||
if not self:
|
||
self.head = self.tail = None
|
||
|
||
def __len__(self):
|
||
return sum(1 for _ in self)
|
||
|
||
def __getitem__(self, idx):
|
||
return next(filter(lambda x: x[0] == idx, enumerate(self)))[1]
|
||
|
||
def __call__(self, key):
|
||
return self[key].data
|
||
|
||
def get_data(self):
|
||
return [*map(ObjList.get_data, self)]
|
||
|
||
|
||
class ObjList:
|
||
def __init__(self, data=None):
|
||
self.__next = None
|
||
self.__prev = None
|
||
self.__data = data
|
||
|
||
def set_next(self, obj):
|
||
self.__next = obj
|
||
|
||
def set_prev(self, obj):
|
||
self.__prev = obj
|
||
|
||
def get_next(self):
|
||
return self.__next
|
||
|
||
def get_prev(self):
|
||
return self.__prev
|
||
|
||
def set_data(self, data):
|
||
self.__data = data
|
||
|
||
def get_data(self):
|
||
return self.__data
|
||
|
||
data = property(get_data, set_data)
|
||
next = property(get_next, set_next)
|
||
prev = property(get_prev, set_prev)
|
||
|
||
|
||
def tests():
|
||
ln = LinkedList()
|
||
ln.add_obj(ObjList("Сергей"))
|
||
ln.add_obj(ObjList("Балакирев"))
|
||
ln.add_obj(ObjList("Python ООП"))
|
||
ln.remove_obj(2)
|
||
assert (
|
||
len(ln) == 2
|
||
), "функция len вернула неверное число объектов в списке, возможно, неверно работает метод remove_obj()"
|
||
ln.add_obj(ObjList("Python"))
|
||
assert ln(2) == "Python", "неверное значение атрибута __data, взятое по индексу"
|
||
assert len(ln) == 3, "функция len вернула неверное число объектов в списке"
|
||
assert ln(1) == "Балакирев", "неверное значение атрибута __data, взятое по индексу"
|
||
|
||
n = 0
|
||
h = ln.head
|
||
while h:
|
||
assert isinstance(h, ObjList)
|
||
h = h._ObjList__next
|
||
n += 1
|
||
|
||
assert n == 3, "при перемещении по списку через __next не все объекты перебрались"
|
||
|
||
n = 0
|
||
h = ln.tail
|
||
while h:
|
||
assert isinstance(h, ObjList)
|
||
h = h._ObjList__prev
|
||
n += 1
|
||
|
||
assert n == 3, "при перемещении по списку через __prev не все объекты перебрались"
|
||
|
||
|
||
if __name__ == "__main__":
|
||
import doctest
|
||
|
||
doctest.testmod()
|
||
tests()
|