This chapter introduces the stack data structure, covering its definition, operations, applications, and implementations in Python, including converting and evaluating expressions in different notations.
In this chapter, we explore the stack data structure. A stack is used to store multiple elements where the elements can be accessed in a specific order. Stacks allow operations to be performed in a Last-In-First-Out (LIFO) manner. This concept is fundamental in both computer science and programming.
A data structure defines how data is organized and accessed. While understanding stacks, we should also be familiar with other data structures like arrays, linked lists, and queues that help to handle data effectively.
A stack behaves like a pile of plates or books. You add to and remove items from the top of the pile. The operations performed on a stack are:
Common real-life examples and programming uses of stacks include:
There are two fundamental stack operations:
If an attempt is made to pop an element from an empty stack, it results in underflow. Conversely, trying to push an element onto a full stack results in overflow. In Python, lists can be utilized to simulate stacks since they allow for dynamic sizing.
Python’s built-in list type can be utilized to implement stacks simply. The methods append() and pop() can be applied for pushing and popping elements. Here’s how to implement a basic stack:
class Stack:
def __init__(self):
self.items = []
def is_empty(self):
return len(self.items) == 0
def push(self, item):
self.items.append(item)
def pop(self):
if not self.is_empty():
return self.items.pop()
return 'underflow'
def size(self):
return len(self.items)
def top(self):
if not self.is_empty():
return self.items[-1]
return 'stack empty'
def display(self):
return self.items[::-1] # returns a reversed list for display
Mathematical expressions can be represented in different formats:
x + y)+xy)xy+)Postfix and prefix notations allow easier evaluation of expressions, eliminating the need for parentheses to indicate order of operations.
Converting infix notation to postfix requires a stack to keep track of operators and their precedence. An algorithm for this conversion involves processing each character, pushing operators to the stack and building the output string accordingly.
Postfix expressions can be evaluated using a stack to store operands. The algorithm involves pushing operands onto the stack and performing operations when an operator is encountered. This is efficient as operators follow operands directly, maintaining a clear order of calculations.