class LinkedListStack(object): """Implements a stack using a double linked list internally. O(1) time complexity for push and pop""" def __init__(self, top=None): self._linked_list = DoublyLinkedList(top) def get_linked_list(self): return self._linked_list def is_empty(self): return self.get_linked_list().is_empty() def push(self, new_node): """"Pushes a new element onto the top of the stack""" self._linked_list.position_insert(new_node, -1) def pop(self): """Removes and returns the first item on the top of the stack""" return self.get_linked_list().remove_head() def peek(self): """Returns the first item on the top of the stack""" return self.get_linked_list().head() def get_size(self): try: return self.get_linked_list().get_length() except IndexError: return 0
def test_pop_one_from_one(): """One element should be removed from a list of size one after pop""" a_list = DoublyLinkedList() a_list.push(0) value = a_list.pop() assert value == 0 assert not a_list
class RingBuffer: def __init__(self, capacity): self.capacity = capacity self.current = None self.storage = DoublyLinkedList() def append(self, item): if self.storage.length < self.capacity: self.storage.add_to_tail(item) elif self.storage.length == self.capacity: if not self.storage.tail.next: self.storage.tail.next = self.storage.head self.current = self.storage.head self.current.value = item self.current = self.current.next def get(self): list_buffer_contents = [] next_node = self.storage.head.next list_buffer_contents.append(self.storage.head.value) for _ in range(self.capacity - 1): if next_node is None: pass else: list_buffer_contents.append(next_node.value) next_node = next_node.next return list_buffer_contents
def test_push_two(): """Two elements should be added to an empty list""" a_list = DoublyLinkedList() a_list.push(0) a_list.push(1) assert len(a_list) == 2 assert a_list.start.next == a_list.end assert a_list.end.prev == a_list.start
def __init__(self, head=None): self._linked_list = DoublyLinkedList(head) self._front = self._linked_list.head() self._rear = self._linked_list.get_end() if not head: self._size = 0 else: self._size = self.get_linked_list().get_length()
def test_make_node(self): data = 5 already_node = Node(1) node = DoublyLinkedList.make_node(data) already_node = DoublyLinkedList.make_node(already_node) self.assertEqual(type(node), Node) self.assertEqual(type(already_node), Node)
class LinkedlistQueue: """ Implements a queue which uses a doubly linked list explicitly internally. This queue keeps both front and rear references so than enqueueing and dequeueing occur in O(1). The queue rear is the head of the linked list, while the queue front is the tail of the linked list. """ def __init__(self, head=None): self._linked_list = DoublyLinkedList(head) self._front = self._linked_list.head() self._rear = self._linked_list.get_end() if not head: self._size = 0 else: self._size = self.get_linked_list().get_length() def get_linked_list(self) -> DoublyLinkedList: return self._linked_list def get_front(self) -> Union[Node, None]: return self._front def set_front(self, node) -> None: self._front = node def get_rear(self) -> Union[Node, None]: return self._rear def set_rear(self, node) -> None: self._rear = node def enqueue(self, data) -> None: """Adds an item to the rear of the queue.""" data = DoublyLinkedList.make_node(data) self._linked_list.position_insert(data, -1) self.set_rear(self._linked_list.head()) self._size += 1 if self.get_size() == 1: self.set_front(data) def dequeue(self) -> Node: """Removes and returns the first item at the front of the queue""" removed = self.get_front() new_front = removed.get_previous() self.set_front(new_front) new_front.set_next(None) removed.clear_connections() self._size -= 1 return removed def is_empty(self) -> bool: return self.get_linked_list().is_empty() def get_size(self) -> int: return self._size def __str__(self): return str(self.get_linked_list())
def test_pop_one_from_three(): """One element should be removed from a list of size three after pop""" a_list = DoublyLinkedList() a_list.push(0).push(1).push(2) a_value = a_list.pop() assert a_value == 2 assert a_list.end.value == 1 assert a_list.start.value == 0 assert len(a_list) == 2
def test_get(self): l = DoublyLinkedList() self.assertIsNone(l.get(1)) l.append(1) self.assertEqual(1, l.get(0)) l.append(2) self.assertEqual(2, l.get(1))
def test_append_get(self): l = DoublyLinkedList(0, -1.0) self.assertEqual(len(l), 2) self.assertEqual(l.get(0), 0) self.assertEqual(l.get(1), -1.0) self.assertEqual(l._head.data, 0) self.assertEqual(l._tail.data, -1.0) self.assertEqual(l._head._next, l._tail) self.assertEqual(l._tail._prev, l._head) self.assertIsNone(l._head._prev) self.assertIsNone(l._tail._next)
def test_index(self): l = DoublyLinkedList() self.assertIsNone(l.index(1)) l.append(1) l.append(1) self.assertEqual(0, l.index(1)) l.append(2) self.assertEqual(2, l.index(2))
def test_equality(): """DoublyLinkedList with same elements in order should be equal""" a_list = DoublyLinkedList() a_list.push(0).push(1).push(2) another_list = DoublyLinkedList() another_list.push(0).push(1).push(2) assert id(another_list) != id(a_list) assert another_list == a_list
def test_equality_unorder(): """DoublyLinkedList with same elements in different order should NOT be equal""" a_list = DoublyLinkedList() a_list.push(0).push(1).push(2) another_list = DoublyLinkedList() another_list.push(1).push(2).push(0) assert id(another_list) != id(a_list) assert another_list != a_list
def test_equality_repeat(): """DoublyLinkedList with different number of occurences should NOT be equal""" a_list = DoublyLinkedList() a_list.push(0).push(1).push(2) another_list = DoublyLinkedList() another_list.push(0).push(0).push(1).push(2) assert id(another_list) != id(a_list) assert another_list != a_list
def test_iterable(): """DoublyLinkedList should be Iterable""" a_list = DoublyLinkedList() assert isinstance(a_list, Iterable) an_iter = iter(a_list) assert isinstance(an_iter, Iterable) assert isinstance(an_iter, Iterator)
def test_creation_empty(): """An empty list should have its attributes set""" a_list = DoublyLinkedList() assert not a_list assert hasattr(a_list, "start") assert hasattr(a_list, "end") assert hasattr(a_list, "length")
def test_contains(): """__contains__ method should be used by 'in' statements""" a_list = DoublyLinkedList([0, 1, 2]) assert 0 in a_list assert 1 in a_list assert 2 in a_list assert 42 not in a_list
def enqueue(self, data) -> None: """Adds an item to the rear of the queue.""" data = DoublyLinkedList.make_node(data) self._linked_list.position_insert(data, -1) self.set_rear(self._linked_list.head()) self._size += 1 if self.get_size() == 1: self.set_front(data)
def test_equality_other_class(): """DoublyLinkedList equality with another class should return NotImplemented""" a_list = DoublyLinkedList() assert a_list.__eq__(0) == NotImplemented assert a_list.__eq__(True) == NotImplemented assert a_list.__eq__(()) == NotImplemented assert a_list.__eq__("test") == NotImplemented assert a_list.__eq__([]) == NotImplemented
def test_pop(self): l = DoublyLinkedList(0, 1, 2, 3, 4) self.assertEqual(l.pop(), 0) self.assertEqual(l.pop(1), 2) self.assertEqual(len(l), 3) self.assertEqual(l.pop(-1), 4) for i in range(len(l)): l.pop() self.assertEqual(len(l), 0)
class LinkedQueue(Queue): """ A linked list implementation of a queue """ def __init__(self): self.list = DoublyLinkedList() self.iterList = iter(self.list) def size(self): """ Return the size of the queue """ return self.list.size() def is_empty(self): """ Return whether or not the queue is empty """ return self.list.is_empty() def peek(self): """ Poll an element from the front of the queue The method throws an error if the queue is empty """ if self.is_empty(): raise Exception('Queue Empty') return self.list.peekFirst() def poll(self): """ Pull an element from the front of the queue The method throws an error if the queue is empty """ if self.is_empty(): raise Exception('Queue Empty') return self.list.removeFirst() def offer(self, elem): """ Add an element at the back of the queue """ self.list.addLast(elem) def __iter__(self): """ Called when iteration is initialized Return an iterator to allow the user to traverse through the elements found inside the queue """ self.iterList = iter(self.list) return self def __next__(self): """ To move to next element """ return next(self.iterList)
def test_delete(self): l = DoublyLinkedList(1, 2, 3) self.assertEqual(1, l.head.data) l.delete(1) self.assertEqual(2, l.head.data) l.delete(3) self.assertEqual(2, l.head.data) self.assertEqual(2, l.tail.data)
def test_pop_two_from_two(): """Two elements should be removed from a list of size one after two pops""" a_list = DoublyLinkedList() a_list.push(0).push(1) a_value = a_list.pop() assert a_value == 1 another_value = a_list.pop() assert another_value == 0 assert not a_list
class LRUCache(): def __init__(self, n): self.hashTable = {} self.linkedList = DoublyLinkedList() self.length = 0 self.capacity = n def insert(self, key, val): if key in self.hashTable: nodeVal = self.hashTable[key].val self.linkedList.remove(nodeVal, key) self.linkedList.add(nodeVal, key) else: if self.length < self.capacity: self.hashTable[key] = self.linkedList.add(val, key) self.length += 1 else: lastNode = self.linkedList.tail.prev self.linkedList.remove(lastNode.val, lastNode.key) del self.hashTable[lastNode.key] self.hashTable[key] = self.linkedList.add(val, key) def remove(self, key): if key in self.hashTable: node = self.hashTable[key] self.linkedList.remove(node.val, key) del self.hashTable[key] self.length -= 1 def __repr__(self): list_str = "" currentNode = self.linkedList.head.next while currentNode != self.linkedList.tail: list_str += f"{currentNode.key}:{currentNode.val} " currentNode = currentNode.next return list_str
def setUp(self): self.n1 = Node(1) self.n2 = Node(2) self.n3 = Node(3) self.n4 = Node(4) self.n5 = Node(5) self.empty_list = DoublyLinkedList() self.empty_head = self.empty_list.head() self.empty_tail = self.empty_list.get_end() self.single_list = DoublyLinkedList(self.n4) self.single_head = self.single_list.head() self.single_tail = self.single_list.get_end() self.linked_list = DoublyLinkedList(self.n1) self.linked_list.append(self.n2) self.head = self.linked_list.head() self.tail = self.linked_list.get_end()
def test_iter(self): to_iterate = list(range(10)) l = DoublyLinkedList(*to_iterate) for i, j in zip(to_iterate, l): self.assertTrue(i == j)
def test_append(self): l = DoublyLinkedList() l.append(1) self.assertEqual(1, l.head.data) self.assertEqual(1, l.tail.data)
def test_insert_get(self): l = DoublyLinkedList() l.insert("two") l.insert(1.0) l.insert(0) self.assertEqual(len(l), 3) self.assertEqual(l._head.data, 0) self.assertEqual(l._head._next.data, 1.0) self.assertEqual(l._head._next._next.data, "two") self.assertEqual(l._head._next._next, l._tail) self.assertEqual(l._head._next, l._tail._prev) self.assertIsNone(l._head._prev) self.assertIsNone(l._tail._next) self.assertEqual(l.get(0), 0) self.assertEqual(l.get(1), 1.0) self.assertEqual(l.get(2), "two") self.assertEqual(l.get(-1), "two") self.assertEqual(l.get(-3), 0) bad = False try: l.get(4) except ValueError: bad = True self.assertTrue(bad) bad = False try: l.get(-4) except ValueError: bad = True self.assertTrue(bad)
def test_empty_init(self): l = DoublyLinkedList() self.assertEqual(len(l), 0)
def test_insert(self): l = DoublyLinkedList() l.insert(1, 0) self.assertEqual(1, l.head.data) self.assertEqual(1, l.tail.data)