def __init__(self, iterable=None):
     """Initialize this queue and enqueue the given items, if any."""
     # Initialize a new linked list to store the items
     self.head = None
     self.tail = None
     # self.size = 0
     self.list = Doubly_LinkedList()
     if iterable is not None:
         for item in iterable:
             self.enqueue(item)
 def test_delete(self):
     ll = Doubly_LinkedList(['A', 'B', 'C'])
     ll.delete('A')
     assert ll.head.data == 'B'  # new head
     assert ll.tail.data == 'C'  # unchanged
     assert ll.size == 2
     ll.delete('C')
     assert ll.head.data == 'B'  # unchanged
     assert ll.tail.data == 'B'  # new tail
     assert ll.size == 1
     ll.delete('B')
     assert ll.head is None  # new head
     assert ll.tail is None  # new head
     assert ll.size == 0
     with self.assertRaises(ValueError):
         ll.delete('X')  # item not in list
 def test_replace(self):
     ll = Doubly_LinkedList(['A', 'B', 'C'])
     ll.replace('A', 'D')
     assert ll.head.data == 'D'  # new head
     assert ll.tail.data == 'C'  # unchanged
     assert ll.size == 3
     ll.replace('B', 'E')
     assert ll.head.data == 'D'  # unchanged
     assert ll.tail.data == 'C'  # unchanged
     assert ll.size == 3
     ll.replace('C', 'F')
     assert ll.head.data == 'D'  # unchanged
     assert ll.tail.data == 'F'  # new tail
     assert ll.size == 3
     with self.assertRaises(ValueError):
         ll.replace('X', 'Y')  # item not in list
 def test_get_at_index(self):
     ll = Doubly_LinkedList(['A', 'B', 'C'])
     assert ll.get_at_index(0) == 'A'  # head item
     assert ll.get_at_index(1) == 'B'  # middle item
     assert ll.get_at_index(2) == 'C'  # tail item
     with self.assertRaises(ValueError):
         ll.get_at_index(3)  # index too high
     with self.assertRaises(ValueError):
         ll.get_at_index(-1)  # index too low
 def test_prepend(self):
     ll = Doubly_LinkedList()
     ll.prepend('C')
     assert ll.head.data == 'C'  # new head
     assert ll.tail.data == 'C'  # new head
     assert ll.size == 1
     ll.prepend('B')
     assert ll.head.data == 'B'  # new head
     assert ll.tail.data == 'C'  # unchanged
     assert ll.size == 2
     ll.prepend('A')
     assert ll.head.data == 'A'  # new head
     assert ll.tail.data == 'C'  # unchanged
     assert ll.size == 3
 def test_insert_at_index(self):
     ll = Doubly_LinkedList()
     ll.insert_at_index(0, 'B')  # append('B')
     assert ll.head.data == 'B'  # new head (at index 0)
     assert ll.tail.data == 'B'  # new tail (at index 0)
     assert ll.size == 1
     ll.insert_at_index(0, 'A')  # prepend('A')
     assert ll.head.data == 'A'  # new head (at index 0)
     assert ll.tail.data == 'B'  # unchanged (now at index 1)
     assert ll.size == 2
     ll.insert_at_index(2, 'D')  # append('D')
     assert ll.head.data == 'A'  # unchanged (at index 0)
     assert ll.tail.data == 'D'  # new tail (now at index 2)
     assert ll.size == 3
     ll.insert_at_index(2, 'C')  # insert 'C' between 'B' and 'D'
     assert ll.head.data == 'A'  # unchanged (at index 0)
     assert ll.tail.data == 'D'  # unchanged (now at index 3)
     assert ll.size == 4
     with self.assertRaises(ValueError):
         ll.insert_at_index(5, 'X')  # index too high
     with self.assertRaises(ValueError):
         ll.insert_at_index(-1, 'Y')  # index too low
 def test_size(self):
     ll = Doubly_LinkedList()
     assert ll.size == 0
     # append and prepend operations increment size
     ll.append('B')
     assert ll.size == 1
     ll.prepend('A')
     assert ll.size == 2
     ll.append('C')
     assert ll.size == 3
     # delete operations decrement size
     ll.delete('B')
     assert ll.size == 2
     ll.delete('C')
     assert ll.size == 1
     ll.delete('A')
     assert ll.size == 0
 def test_length(self):
     ll = Doubly_LinkedList()
     assert ll.length() == 0
     # append and prepend operations increase length
     ll.append('B')
     assert ll.length() == 1
     ll.prepend('A')
     assert ll.length() == 2
     ll.append('C')
     assert ll.length() == 3
     # delete operations decrease length
     ll.delete('B')
     assert ll.length() == 2
     ll.delete('C')
     assert ll.length() == 1
     ll.delete('A')
     assert ll.length() == 0
 def test_items(self):
     ll = Doubly_LinkedList()
     assert ll.items() == []
     ll.append('B')
     assert ll.items() == ['B']
     ll.prepend('A')
     assert ll.items() == ['A', 'B']
     ll.append('C')
     assert ll.items() == ['A', 'B', 'C']
 def test_init_with_list(self):
     ll = Doubly_LinkedList(['A', 'B', 'C'])
     assert ll.head.data == 'A'  # first item
     assert ll.tail.data == 'C'  # last item
     assert ll.size == 3
 def test_init(self):
     ll = Doubly_LinkedList()
     assert ll.head is None
     assert ll.tail is None
     assert ll.size == 0
 def test_find(self):
     ll = Doubly_LinkedList(['A', 'B', 'C'])
     assert ll.find(lambda item: item == 'B') == 'B'
     assert ll.find(lambda item: item < 'B') == 'A'
     assert ll.find(lambda item: item > 'B') == 'C'
     assert ll.find(lambda item: item == 'X') is None
class Doubly_LinkedQueue(object):
    def __init__(self, iterable=None):
        """Initialize this queue and enqueue the given items, if any."""
        # Initialize a new linked list to store the items
        self.head = None
        self.tail = None
        # self.size = 0
        self.list = Doubly_LinkedList()
        if iterable is not None:
            for item in iterable:
                self.enqueue(item)

    def __repr__(self):
        """Return a string representation of this queue."""
        return 'Queue({} items, front={})'.format(self.length(), self.front())

    def is_empty(self):
        """Return True if this queue is empty, or False otherwise."""
        # TODO: Check if empty
        return self.list.head is None

    def length(self):
        """Return the number of items in this queue."""
        # TODO: Count number of items
        return self.list.length()
        print(self.length)

    def enqueue_back(self, item):
        """Insert the given item at the back of this queue.
        Running time: O(???) – Why? [TODO]"""
        # TODO: Insert given item
        #Append to the end of the list
        self.list.append(item)

    def enqueue_front(self, item):
        # TODO: Insert given item
        # Move the item to the start of the list
        self.list.prepend(item)

    def front(self):
        """Return the item at the front of this queue without removing it,
        or None if this queue is empty."""
        # TODO: Return front item, if any
        if self.is_empty():
            #raise ValueError
            return None
        #return self.list.head.data
        self.list.pop(-1)

    def back(self):
        if self.is_empty():
            return None
        return self.list.tail.data

    def dequeue_front(self):
        """Remove and return the item at the front of this queue,
        or raise ValueError if this queue is empty.
        Running time: O(???) – Why? [TODO]"""
        # TODO: Remove and return front item, if any
        #Check if head is empty
        if self.is_empty():
            raise ValueError

        #Set the data to the tail
        data = self.list.tail.data
        self.list.delete(self.list.tail.data)
        return data

    def dequeue_back(self):

        #Check if head is empty
        if self.is_empty():
            raise ValueError

        #Set the data to the head
        data = self.list.head.data
        self.list.delete(self.list.head.data)
        return data