py_stepik/mod_oop/3.3_07_linkedlist.py
2024-04-11 16:15:07 +03:00

173 lines
6.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
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()