class Stack: def __init__(self): self.size = 0 # Why is our DLL a good choice to store our elements? # we will be adding and subtracting based on LIFO self.storage = DoublyLinkedList() def push(self, value): # add to the top of the stack, aka the tail # increment size by 1 self.size += 1 self.storage.add_to_tail(value) def pop(self): # check if size > 0 # if true: # remove from the top of the stack, aka the tail # decrement size by 1 # else return None if self.size > 0: self.size -= 1 return self.storage.remove_from_tail() else: return None def len(self): return self.size
class Queue: def __init__(self): self.size = 0 # Why is our DLL a good choice to store our elements? # it has directional pointers so we know # where something is in the 'queue' self.storage = DoublyLinkedList() def enqueue(self, value): # take the dll # run add to tail and pass it value self.storage.add_to_head(value) self.size += 1 def dequeue(self): # check if size > 0 # if yes, dequeue # take the dll # run add remove from tail # decrement size by 1 # if not, return None if self.size > 0: self.size -= 1 return self.storage.remove_from_tail() else: return None def len(self): # return size of queue return self.size
class LRUCache: def __init__(self, limit=10): self.limit = limit self.length = 0 self.dll = DoublyLinkedList() """ Retrieves the value associated with the given key. Also needs to move the key-value pair to the top of the order such that the pair is considered most-recently used. Returns the value associated with the key or None if the key-value pair doesn't exist in the cache. """ def get(self, key): found = self.dll.search(key) if found is None: return None self.dll.move_to_front(found) return found.value[key] """ Adds the given key-value pair to the cache. The newly- added pair should be considered the most-recently used entry in the cache. If the cache is already at max capacity before this entry is added, then the oldest entry in the cache needs to be removed to make room. Additionally, in the case that the key already exists in the cache, we simply want to overwrite the old value associated with the key with the newly-specified value. """ def set(self, key, value): found = self.dll.search(key) if found is not None: found.value[key] = value self.dll.move_to_front(found) else: if self.length == self.limit: self.dll.remove_from_tail() else: self.length += 1 self.dll.add_to_head({key: value})
class TextBuffer: def __init__(self, initial_text=None): # the contents of our buffer are stored as a linked list self.contents = DoublyLinkedList() """ if we are passed in initial text as an argument loop through the string and make linked list nodes with every letter """ if initial_text: for char in initial_text: self.contents.add_to_tail(char) # print the contents of our text buffer # O(n) def __str__(self): s = "" """ loop through the linked list add each letter to the string """ current = self.contents.head while current: # concatenate the current letter with the string s += current.value # move to the next item in the list current = current.next # __str__ must return a string return s def append(self, string_to_add): """ loop through the string add each char to the tail """ for char in string_to_add: self.contents.add_to_tail(char) def prepend(self, string_to_add): """ reverse the incoming string then loop through it and add each char to the head """ for char in string_to_add[::-1]: self.contents.add_to_head(char) def delete_front(self, chars_to_remove): """ takes in an argument for how many chars to delete from the front """ for _ in range(chars_to_remove): self.contents.remove_from_head() def delete_back(self, chars_to_remove): """ takes in an argument for how many chars to delete from the back """ for _ in range(chars_to_remove): self.contents.remove_from_tail() """ Joins another buffer to itself The tail of the current buffer will be the tail of other_buffer The head of other_buffer will become the head of this buffer """ def join(self, other_buffer): # make sure other_buffer is a TextBuffer if not isinstance(other_buffer, TextBuffer): print("Join only accepts TextBuffers") return # set the the current tail to be the tail of the other buffer self.contents.tail.next = other_buffer.contents.head # set the prev property on other_buffer's head to be the tail other_buffer.contents.head.prev = self.contents.tail # set the other buffers head to be the current buffer's other_buffer.contents.head = self.contents.head # set the tail of the current buffer to be other_buffer's tail self.contents.tail = other_buffer.contents.tail """ takes in a string creates a new text buffer out of that string then calls self.join """ def join_string(self, string_to_join): new_buffer = TextBuffer(string_to_join) self.join(new_buffer)
class DoublyLinkedListTests(unittest.TestCase): def setUp(self): self.node = ListNode(1) self.dll = DoublyLinkedList(self.node) def test_list_remove_from_tail(self): self.dll.remove_from_tail() self.assertIsNone(self.dll.head) self.assertIsNone(self.dll.tail) self.assertEqual(len(self.dll), 0) self.dll.add_to_tail(33) self.assertEqual(self.dll.head.value, 33) self.assertEqual(self.dll.tail.value, 33) self.assertEqual(len(self.dll), 1) self.assertEqual(self.dll.remove_from_tail(), 33) self.assertEqual(len(self.dll), 0) self.dll.add_to_tail(68) self.assertEqual(len(self.dll), 1) self.assertEqual(self.dll.remove_from_tail(), 68) self.assertEqual(len(self.dll), 0) def test_list_remove_from_head(self): self.dll.remove_from_head() self.assertIsNone(self.dll.head) self.assertIsNone(self.dll.tail) self.assertEqual(len(self.dll), 0) self.dll.add_to_head(2) self.assertEqual(self.dll.head.value, 2) self.assertEqual(self.dll.tail.value, 2) self.assertEqual(len(self.dll), 1) self.assertEqual(self.dll.remove_from_head(), 2) self.assertEqual(len(self.dll), 0) self.dll.add_to_head(55) self.assertEqual(len(self.dll), 1) self.assertEqual(self.dll.remove_from_head(), 55) self.assertEqual(len(self.dll), 0) def test_list_add_to_tail(self): self.assertEqual(self.dll.tail.value, 1) self.assertEqual(len(self.dll), 1) self.dll.add_to_tail(30) self.assertEqual(self.dll.tail.prev.value, 1) self.assertEqual(self.dll.tail.value, 30) self.assertEqual(len(self.dll), 2) self.dll.add_to_tail(20) self.assertEqual(self.dll.tail.prev.value, 30) self.assertEqual(self.dll.tail.value, 20) self.assertEqual(len(self.dll), 3) def test_node_delete(self): node_1 = ListNode(3) node_2 = ListNode(4) node_3 = ListNode(5) node_1.next = node_2 node_2.next = node_3 node_2.prev = node_1 node_3.prev = node_2 node_2.delete() self.assertEqual(node_1.next, node_3) self.assertEqual(node_3.prev, node_1) def test_node_insert_before(self): self.node.insert_before(0) self.assertEqual(self.node.prev.value, 0) def test_list_add_to_head(self): self.assertEqual(self.dll.head.value, 1) self.dll.add_to_head(10) self.assertEqual(self.dll.head.value, 10) self.assertEqual(self.dll.head.next.value, 1) self.assertEqual(len(self.dll), 2) def test_node_insert_after(self): self.node.insert_after(2) self.assertEqual(self.node.next.value, 2) def test_list_move_to_end(self): self.dll.add_to_head(40) self.assertEqual(self.dll.tail.value, 1) self.assertEqual(self.dll.head.value, 40) self.dll.move_to_end(self.dll.head) self.assertEqual(self.dll.tail.value, 40) self.assertEqual(self.dll.tail.prev.value, 1) self.assertEqual(len(self.dll), 2) self.dll.add_to_tail(4) self.dll.move_to_end(self.dll.head.next) self.assertEqual(self.dll.tail.value, 40) self.assertEqual(self.dll.tail.prev.value, 4) self.assertEqual(len(self.dll), 3) def test_list_move_to_front(self): self.dll.add_to_tail(3) self.assertEqual(self.dll.head.value, 1) self.assertEqual(self.dll.tail.value, 3) self.dll.move_to_front(self.dll.tail) self.assertEqual(self.dll.head.value, 3) self.assertEqual(self.dll.head.next.value, 1) self.assertEqual(len(self.dll), 2) self.dll.add_to_head(29) self.dll.move_to_front(self.dll.head.next) self.assertEqual(self.dll.head.value, 3) self.assertEqual(self.dll.head.next.value, 29) self.assertEqual(len(self.dll), 3) def test_list_delete(self): self.dll.delete(self.node) self.assertIsNone(self.dll.head) self.assertIsNone(self.dll.tail) self.assertEqual(len(self.dll), 0) self.dll.add_to_tail(1) self.dll.add_to_head(9) self.dll.add_to_tail(6) self.dll.delete(self.dll.head) self.assertEqual(self.dll.head.value, 1) self.assertEqual(self.dll.tail.value, 6) self.assertEqual(len(self.dll), 2) self.dll.delete(self.dll.head) self.assertEqual(self.dll.head.value, 6) self.assertEqual(self.dll.tail.value, 6) self.assertEqual(len(self.dll), 1) def test_get_max(self): self.assertEqual(self.dll.get_max(), 1) self.dll.add_to_tail(100) self.assertEqual(self.dll.get_max(), 100) self.dll.add_to_tail(55) self.assertEqual(self.dll.get_max(), 100) self.dll.add_to_tail(101) self.assertEqual(self.dll.get_max(), 101)