starting linked lists

This commit is contained in:
Stefan Harmuth 2022-01-14 10:19:30 +01:00
parent ed90adc75c
commit e239196065

167
tools/lists.py Normal file
View File

@ -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)