+ 3.3_07
This commit is contained in:
parent
fb4a932136
commit
360f71e61e
172
mod_oop/3.3_07_linkedlist.py
Normal file
172
mod_oop/3.3_07_linkedlist.py
Normal file
@ -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()
|
Loading…
Reference in New Issue
Block a user