py_stepik/mod_oop/3.3_07_linkedlist.py

173 lines
6.4 KiB
Python
Raw Permalink Normal View History

2024-04-11 13:11:43 +00:00
"""
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()