Ejemplo n.º 1
0
class LRUCache:
    """
    Our LRUCache class keeps track of the max number of nodes it
    can hold, the current number of nodes it is holding, a doubly-
    linked list that holds the key-value entries in the correct 
    order, as well as a storage dict that provides fast access
    to every node stored in the cache.
    """
    def __init__(self, limit=10):
        self.limit = limit
        self.cache = DoublyLinkedList()

    """
    Retrieves the value associated with the given key. Also
    needs to move the key-value pair to the end 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):
        current_node = self.cache.head
        next_node = self.cache.head.next if self.cache.head is not None else None
        while current_node is not None:
            if current_node.key == key:
                ret_val = current_node.value
                self.cache.move_to_end(current_node)
                return ret_val
            current_node = next_node
            if current_node is not None:
                next_node = current_node.next
        return None

    """
    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):
        # Looking for key in list
        current_node = self.cache.head
        next_node = self.cache.head.next if self.cache.head is not None else None
        while current_node is not None:
            if current_node.key == key:
                current_node.value = value
                self.cache.move_to_end(current_node)
                #Leave function
                return
            # Increment
            current_node = next_node
            if current_node is not None:
                next_node = current_node.next

        #If we haven't found the key, we need to add it
        if self.cache.length < self.limit:
            self.cache.add_to_tail(value, key)
        else:
            self.cache.remove_from_head()
            self.cache.add_to_tail(value, key)
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)
class RingBuffer:
    def __init__(self, capacity):
        self.capacity = capacity
        self.current = None
        self.storage = DoublyLinkedList()
        self.items = []

    def append(self, item):
        # create an empty list to keep track of oldest element
        # if self.size is not self.capacity
        if self.storage.length < self.capacity:
            # add item to end of self.storage
            self.storage.add_to_tail(item)
            self.current = self.storage.head
            self.items.append(self.current)
        # if self.size is self.capacity
        elif self.storage.length == self.capacity:
            # remove head and add to tail
            remove_head = self.storage.head
            # print(len(self.items))
            if remove_head in self.items:
                self.items.remove(remove_head)
            # print(len(self.items))
            # print(remove_head)
            self.storage.remove_from_head()
            self.storage.add_to_tail(item)
            # self

            # Reset current position to tail
            if remove_head == self.current:
                self.current = self.storage.tail

    def get(self):
        # Note:  This is the only [] allowed
        list_buffer_contents = []

        # TODO: Your code here
        current_node = self.current
        list_buffer_contents.append(current_node.value)
        if current_node.next:
            next_node = current_node.next
        else:
            next_node = self.storage.head  # from the top
        # iterate till current node
        while next_node != current_node:
            list_buffer_contents.append(next_node.value)
            if next_node.next:  # node to the right? set next_node
                next_node = next_node.next
            else:
                next_node = self.storage.head  # go back to head

        ######### Almost worked!!
        # while self.storage.length > 0:

        #     current_head = self.storage.remove_from_head()
        #     print(self.storage)
        #     if current_head:
        #         list_buffer_contents.append(current_head)
        #         # self.items.pop(0)
        #     # print(current_head)
        return list_buffer_contents