from dataclasses import dataclass from typing import Any, Union @dataclass class Node: value: Any next: 'Node' = None prev: 'Node' = None class Stack: _tail: Node = None size: int = 0 def push(self, obj: Any): self._tail = Node(obj, self._tail) self.size += 1 def pop(self) -> Any: if self._tail is None: raise ValueError('No more objects on stack') res = self._tail.value self._tail = self._tail.next self.size -= 1 return res def peek(self) -> Any: if self._tail is None: raise ValueError('No more objects on stack') return self._tail.value def __contains__(self, obj: Any) -> bool: x = self._tail while x.value != obj and x.next is not None: x = x.next return x.value == obj class Queue: pass class LinkedList: _head: Union[Node, None] = None _tail: Union[Node, None] = None size: int = 0 def _append(self, obj: Any): node = Node(obj) if self._head is None: self._head = node if self._tail is None: self._tail = node else: self._tail.next = node node.prev = self._tail self._tail = node self.size += 1 def _insert(self, index: int, obj: Any): i_node = Node(obj) node = self._get_node(index) i_node.prev, i_node.next = node.prev, node node.prev = i_node if node.prev is not None: node.prev.next = i_node if index == 0: self._head = i_node if index == self.size - 1: self._tail = i_node self.size += 1 def _get_node(self, index: int) -> Node: if abs(index) >= self.size: raise IndexError("index out of bounds") if index < 0: index = self.size + index if index <= self.size // 2: x = 0 node = self._head while x < index: x += 1 node = node.next else: x = self.size - 1 node = self._tail while x > index: x -= 1 node = node.prev return node def _get(self, index: int) -> Any: return self._get_node(index).value def _pop(self, index: int = None) -> Any: if self.size == 0: raise IndexError("pop from empty list") if index is None: # pop from the tail node = self._tail if self.size > 1: self._tail = self._tail.prev self._tail.next = None else: self._head = None self._tail = None ret = node.value elif index == 0: # pop from the head node = self._head if self.size > 1: self._head = self._head.next self._head.prev = None else: self._head = None self._tail = None ret = node.value else: node = self._get_node(index) if node.prev is not None: node.prev.next = node.next if node.next is not None: node.next.prev = node.prev node.prev = None node.next = None ret = node.value self.size -= 1 return ret def append(self, obj: Any): self._append(obj) def insert(self, index: int, obj: Any): self._insert(index, obj) def get(self, index: int) -> Any: return self._get(index) def pop(self, index: int = None) -> Any: return self._pop(index) def debug(self): print("head:", self._head) print("tail:", self._tail) if self.size > 0: x = 0 o = self._head print(x, o.value) while o.next is not None: x += 1 o = o.next print(x, o.value)