From e239196065db2dba0b33217d20a704c9ffeff021 Mon Sep 17 00:00:00 2001 From: Stefan Harmuth Date: Fri, 14 Jan 2022 10:19:30 +0100 Subject: [PATCH] starting linked lists --- tools/lists.py | 167 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 tools/lists.py diff --git a/tools/lists.py b/tools/lists.py new file mode 100644 index 0000000..5905196 --- /dev/null +++ b/tools/lists.py @@ -0,0 +1,167 @@ +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)