def test_pop_until_empty(): s = Stack() s.push("apple") s.push("banana") s.push("cucumber") s.pop() s.pop() s.pop() actual = s.is_empty() expected = True assert actual == expected
def test_pop_some(): s = Stack() s.push("apple") s.push("banana") s.push("cucumber") s.pop() actual = s.pop() expected = "banana" assert actual == expected
class MyQueue(): """Queue implemented using 2 stacks Swap all elements between stacks when need to swap between pushing and popping """ def __init__(self): """Initialise push and pop stacks """ # Create stack elements need to be on when adding to queue self.add_stack = Stack() # Create stack elements need to be on when removing from queue self.remove_stack = Stack() # Use boolean to track last operation self.just_added = True # Note: could just check if relevant stack is empty, rather than using # this flag def _swap_elements(self, stack_1, stack_2): """Put all elements in stack_1 into stack_2 Parameters ---------- stack_1 : Stack Stack to remove elements from stack_2 : Stack Stack to put elements onto """ while not stack_1.is_empty(): element = stack_1.pop() stack_2.push(element) def add(self, data): """Add element to back of queue, swapping stacks if required Parameters ---------- data : any Data to store in queue; can be any python object """ if not self.just_added: # Need to swap stacks, so we can add to back of queue self._swap_elements(self.remove_stack, self.add_stack) # Update bool self.just_added = True # Add element to back of queue self.add_stack.push(data) def remove(self): """Remove element from front of queue, swapping stack if required Returns ------- data : any Data at front of queue; can be any Python object. """ if self.just_added: # Need to swap stacks, so we can remove from front of queue self._swap_elements(self.add_stack, self.remove_stack) # Update bool self.just_added = False # Remove element return self.remove_stack.pop()
def test_pop_empty(): s = Stack() with pytest.raises(InvalidOperationError) as e: s.pop() assert str(e.value) == "Method not allowed on empty collection"
def test_pop_single(): s = Stack() s.push("apple") actual = s.pop() expected = "apple" assert actual == expected
class StackMin2(Stack): """More efficient version of StackMin Doesn't store extra piece of data (min value) at every node, since this is v. inefficient if, say, first node is min value, and there are many nodes above it. Instead, use another stack to keep track of min value when it changes. Note that adding another element with value equal to the current min value does add to this stack, since otherwise removing this element would break get_min() (this wasn't clear in book's solution). ^Above solution based on book's solution. """ def __init__(self): """Initialise stack as is done for Stack, but also introduce stack to track min values """ # Initialise Stack super().__init__() # Use this stack to track min vals self.min_vals = Stack() def get_min(self): """Returns min value in stack Returns ------- min_val : any Minimum value of sub-stack. Can be any Python object that allows comparison. """ return self.min_vals.peek() def push(self, data): """Add item (data) to top of stack (i.e. to head of Stack). Ensure to add info about min of sub-array Parameters ---------- data Data to store in stack. """ # Find exising min_val # Handle special case of empty stack if self.head is None: self.min_vals.push(data) else: min_val = self.get_min() if data <= min_val: self.min_vals.push(data) # Add data to stack self.prepend(data) def pop(self): """Remove and return the top item from the stack. Returns ------- any Data at head of Stack. Can be any Python object that allows comparison. """ if self.head is None: raise Exception('{} is empty.'.format(self.__name__)) # Retrieve head node data, then delete head node data = self.head.data self._delete_head() # Remove element from min_vals stack, if required if data == self.min_vals.peek(): self.min_vals.pop() return data