diff --git a/mod_oop/3.3_07_linkedlist.py b/mod_oop/3.3_07_linkedlist.py new file mode 100644 index 0000000..a74d0d6 --- /dev/null +++ b/mod_oop/3.3_07_linkedlist.py @@ -0,0 +1,172 @@ +""" + 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()