Python数据结构与算法中的栈详解(2)
本文将深入探讨栈的应用和实现。我们将介绍栈在括号匹配、函数调栈、逆波兰表达式求值和中缀表达式转换为逆波兰表达式中的应用,并提供使用列表和链表实现栈的示例。
栈应用
1. 括号匹配
栈可以用于检查括号是否匹配。我们可以遍历字符串中的每个字符,如果是左括号,则将其压入栈中;如果是右括号,则将其与栈顶元素进行匹配。如果匹配成功,则将栈顶元素弹出;否则,字符串不合法。
下面是一个示例,用于演示如何使用栈检查括号是否匹配。
def is_valid_parentheses(s):
stack = []
mapping = {')': '(', '}': '{', ']': '['}
for char in s:
if char in mapping:
top_element = stack.pop() if stack else '#'
if mapping[char] != top_element:
return False
else:
stack.append(char)
return not stack
在这个示例中,我们定义了一个is_valid_parentheses()函数,它接受一个字符串作为返回一个布尔值,表示括号是否匹配。我们使用栈来存储左括号,并使用一个字典来存储左右括号之间的映射关系。我们遍历字符串中的每个字符如果是左括号,则将其压入栈中;如果是右括号,则将其与栈顶元素进行匹配。如果匹配,则将栈元素弹出;否则,字符串不合法。最后,如果栈为空,则表示括号匹配成功。
2. 函数调用栈
在Python中,每次函数调用都创建一个新的栈帧。栈帧包含函数的局部变量、参数和返回地址等信息。当函数返回时,栈帧被弹出,控权返回到调用函数的位置。
下面是一个示例,用于演示函数调用栈的工作原理。
def foo():
print('foo')
bar()
def bar():
print('bar')
foo()
在这个示例中,我们定义了两个函数foo()和bar(),并在foo()函数中调用了bar()函数。当我们运行这个时,Python会创建一个新的栈帧存储foo()函数的局部变量、参数和返回地址等信息。然后,foo()函数调用bar()函数,Python会创建另一个栈帧来存储bar()函数的局部变量、参数和返回地址等信息。当bar()函数返回时,Python会弹出bar()函数的栈帧,并将控制权返回到foo()函数。最后,当foo()函数返回时,Python会弹出foo()函数的帧,并将控制权返回到主程序。
3. 逆波兰表达式求值
逆波兰表达式是一种不需要括号的数学表达式表示方法。在逆波兰表达式中,操作符在操作数的后面,而不是在操作数的中间。例如,表达式“2 + 3”可以写成“2 3 +”。
我们可以栈来求解逆波兰表达式。我们遍历表达式中的每个元素,如果元素是操作数,则将其压入栈中;如果元素是操作符,则从栈中弹出两个操作数,并将它们应用于操作符。最后,栈中剩下的元素就是表达式的值。
下面是一个示例,用于演示如何栈实现逆波兰表达式求值。
def eval_rpn(tokens):
stack = []
for in tokens:
if token in ['+', '-', '*', '/']:
b = stack.pop()
a = stack.pop()
if token == '+':
stack.append(a + b)
elif token == '-':
stack.append(a - b)
elif token == '*':
stack.append(a * b)
elif token == '/':
stack.append(int(a / b))
else:
stack.append(int(token))
return stack.pop()
在这个示例中,我们定义了一个eval_rpn()函数,它接受一个逆波兰表达式作为参数,并返回表达式的值。我们使用一个栈来存储操作数,并遍历表达中的每个元素。如果元素是操作符,则从栈中弹出两个操作数,并将它们应用于操作符。如果元素是操作数,则将其压入栈中。最后,栈中剩下的元素就是表达的值。
4. 中缀表达式转换为逆波兰表达式
中缀表达式是我们通常使用的数学表达式表示方法。在中缀表达式中,操作符在操作数的中间,而不是在操作数的后面。例如,表达式“2 + 3”就是一个中缀表达式。
我们可以使用栈将中缀表达式转换为逆波兰表达式。我们遍历表达式中的每个元素,如果元素是操作数,则将其添加到列表中;如果元素是操作符,则将其与栈顶元素进行比较。如果栈顶元素的优先级大于或等于当前操作符的优先级,则将栈顶元弹出并添加到输出中。最后,我们将剩余的运算符弹出并添加到输出列表中。
下面是一个示例,用于演示如何使用栈实现中缀表达式转换为逆波兰表达式。
def infix_to_rpn(expr):
stack = []
output = []
precedence = {'+': 1, '-': 1, '*': 2, '/': 2}
for token in expr:
if token.isdigit():
output.append(token)
elif token in ['+', '-', '*', '/']:
while stack and stack[-1] != '(' and precedence[token] <= precedence.get(stack[-1], 0):
output.append(stack.pop())
stack.append(token)
elif token == '(':
stack.append(token)
elif token == ')':
while stack and stack[-1] != '(':
output.append(stack.pop())
stack.pop()
while stack:
output.append(stack.pop())
return output
在这个示例中,我们定义了一个infix_to_rpn()函数,它接受一个中缀表达式作为参数,并返回一个波兰表达式。我们使用一个栈来存储运算符,并遍历表达式中的每个元素。如果元素是操作数,则将添加到输出列表中。如果元素是操作符,则将其与栈顶元素进行比较。如果栈顶元素的优先级大于或等于当前操作符的优先级,则将栈顶元弹出并添加到输出列表。最后,我们将剩余的运算符弹出并添加到输出列表中。
栈实现
1. 使用列表实现栈
在Python中,我们可以使用列表来实现栈。列表的append()方法可以用于将元素压入栈中,而pop()方法可以用于弹出栈顶元素。
下面是一个示例,用于演示如何使用列表实现栈。
class Stack:
def __init__(self):
self.items = []
def is_empty(self):
return not bool(self.items)
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
return self.items[-1] if self.items else None
def size(self):
return len(self.items)
在这个示例中,我们定义了一个Stack类,它包含_empty()、push()、pop()、peek()和size()等方法。我们使用一个列表来存储栈中的元素。is_empty()方法用于检查栈是否为空;push()方法于将元素压入中;pop()方法用于弹出栈顶元素;peek()方法用于返回栈顶元素size()方法用于返回栈的大小。
2. 使用链表实现栈
在Python中,我们也可以使用链表来实现栈。链表的头部可以用于存储栈顶元素,而每个可以用于存储元素和下一个节点的引用。
下面是一个示例,用于演示如何使用链表实现栈。
class Node:
def __init__(self, data=None):
self.data = data
self.next = None
class Stack:
def __init__(self):
self.top = None
def is_empty(self):
return not bool(self.top)
def push(self, data):
new_node = Node(data)
new_node.next = self.top
self.top = new_node
def pop(self):
if self.top:
data = self.top.data
self.top = self.top.next
return data
else:
return None
def peek(self):
return self.top.data if self.top else None
def size(self):
count = 0
current = self.top
while current:
count += 1
current = current.next
return count
在这个示例中,我们定义了一个Node类,它包含一个数据属性和一个下一个节点的引用。我们还定义了一个Stack类,包含一个头部节点。is_empty()方法用于检查栈是否为空;push()方法用于将元素压入栈;pop()方法用于弹出栈顶元素;peek()方法用于返回栈顶元素;size()方法用于栈的大小。
结论
本文深入探讨了栈的应用和实现。我们介绍了栈在括号匹配、函数调用、逆波兰表达式求值和中缀表达式转换为逆波兰表达式中的应用,并提供使用列表和链表实现栈的示例。在实际应用中,我们可以根据具体的问题选择不同的栈实现方式结合其他数据结构和算法进行合处理,实现复杂的计算任务的求解。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python数据结构与算法中的栈详解(2) - Python技术站