diff --git a/data_structures/stacks/stack_tracking_min_max.py b/data_structures/stacks/stack_tracking_min_max.py new file mode 100644 index 000000000..7aaf5ded1 --- /dev/null +++ b/data_structures/stacks/stack_tracking_min_max.py @@ -0,0 +1,145 @@ +""" +Python3 stack implementation that retrieves min/max elements of the stack in constant time +""" +from __future__ import annotations +import math + +""" +Data object for stack +""" +class StackData: + def __init__(self, current_value: float, min_value: float, max_value: float) -> None: + self.current_value = current_value + self.min_value = min_value + self.max_value = max_value + +""" +Main stack implementation +""" +class MinMaxStack: + def __init__(self, max_stack_size: int = 10) -> None: + self.max_size = max_stack_size + self.stack = [] + + def push_value(self, value: float) -> bool: + """ + >>> test_stack = MinMaxStack(3) + >>> test_stack.push_value(1) + True + >>> test_stack.push_value(2) + True + >>> test_stack.push_value(3) + True + >>> test_stack.push_value(4) + Traceback (most recent call last): + ... + Exception: Max stack size reached. Remove elements before adding new ones or increase stack size. + + """ + + if len(self.stack) == self.max_size: + raise Exception("Max stack size reached. Remove elements before adding new ones or increase stack size.") + + if len(self.stack) == 0: + self.stack.append(StackData(value, value, value)) + else: + """Store min/max values with current value""" + + new_min = min(self.stack[-1].min_value, value) + new_max = max(self.stack[-1].max_value, value) + self.stack.append(StackData(value, new_min, new_max)) + + return True + + def pop_value(self) -> float: + """ + >>> test_stack = MinMaxStack() + >>> test_stack.push_value(1) + True + >>> test_stack.push_value(2) + True + >>> test_stack.pop_value() + 2 + >>> test_stack.pop_value() + 1 + >>> test_stack.pop_value() + Stack is empty + -inf + """ + + if self.stack_is_valid(): + return self.stack.pop().current_value + + return -math.inf + + def get_current_max(self) -> float: + """ + test_stack = MinMaxStack(3) + >>> test_stack.push_value(-450.45) + True + >>> test_stack.push_value(450.45) + True + >>> test_stack.push_value(0) + True + >>> test_stack.get_current_max() + 450.45 + >>> test_stack.pop_value() + 0 + >>> test_stack.get_current_max() + 450.45 + >>> test_stack.pop_value() + 450.45 + >>> test_stack.get_current_max() + -450.45 + >>> test_stack.pop_value() + -450.45 + >>> test_stack.get_current_max() + Stack is empty + -inf + """ + if self.stack_is_valid(): + return self.stack[-1].max_value + + return -math.inf + + def get_current_min(self) -> float: + """ + >>> test_stack = MinMaxStack(3) + >>> test_stack.push_value(123) + True + >>> test_stack.push_value(-123) + True + >>> test_stack.push_value(0) + True + >>> test_stack.get_current_min() + -123 + >>> test_stack.pop_value() + 0 + >>> test_stack.get_current_min() + -123 + >>> test_stack.pop_value() + -123 + >>> test_stack.get_current_min() + 123 + >>> test_stack.pop_value() + 123 + >>> test_stack.get_current_min() + Stack is empty + -inf + """ + if self.stack_is_valid(): + return self.stack[-1].min_value + + return -math.inf + + def stack_is_valid(self) -> bool: + if len(self.stack) == 0: + print("Stack is empty") + return False + + return True + + +if __name__ == "__main__": + from doctest import testmod + testmod() \ No newline at end of file