栈(Stack)是一种线性数据结构,具有后进先出(LIFO)的特性。它可以理解为一种类似于抽屉的容器,只能在顶部进行插入和删除操作,其他位置不可访问。栈的基本操作包括入栈(push)和出栈(pop),其中入栈将元素放入栈顶,出栈将栈顶元素移出。
栈在计算机科学和软件开发中有广泛的应用场景,以下是一些常见的使用场景:
1. 表达式求值:栈可以用于解析和计算数学表达式,如中缀表达式转换为后缀表达式,并利用栈进行后缀表达式的求值。
2. 函数调用:在程序执行过程中,每次函数调用时会将当前函数的上下文保存到栈中,包括局部变量、返回地址等。当函数执行完毕后,从栈中取出上一个函数的上下文并恢复执行。
3. 浏览器的历史记录:浏览器通过栈结构来管理用户访问页面的历史记录。每次用户访问一个新页面时,将该页面的 URL 压入栈中;当用户点击返回按钮时,从栈中弹出最近访问的页面 URL,以便回退到上一个页面。
4. 撤销操作:许多应用程序支持撤销操作,其中栈被用于存储每个操作的状态或内容。当用户选择撤销操作时,可以从栈中逐步恢复先前的状态。
5. 地址转跳:在汇编语言和操作系统设计中,栈被用于存储函数调用期间的返回地址。这使得函数可以通过将返回地址压入栈中并使用跳转指令来返回到调用者。
6. 括号匹配:栈可以用于检查表达式中的括号是否匹配。遍历表达式,当遇到左括号时将其压入栈中,当遇到右括号时,若栈顶元素为匹配的左括号,则将栈顶元素弹出,否则说明括号不匹配。
总之,栈是一个非常有用的数据结构,在许多算法和程序设计的场景中都发挥着重要作用,它提供了一种便捷的方式来实现后进先出的操作。
python源码实现
以下是一个使用栈完成表达式计算的示例代码:
class Stack:
def __init__(self):
self.stack = []
def is_empty(self):
return len(self.stack) == 0
def push(self, item):
self.stack.append(item)
def pop(self):
if not self.is_empty():
return self.stack.pop()
else:
raise IndexError("Stack is empty")
def top(self):
if not self.is_empty():
return self.stack[-1]
else:
raise IndexError("Stack is empty")
def calculate_expression(expression):
# 定义操作符优先级
priority = {'+': 1, '-': 1, '*': 2, '/': 2}
def apply_operator(operator_stack, operand_stack):
operator = operator_stack.pop()
operand2 = operand_stack.pop()
operand1 = operand_stack.pop()
if operator == '+':
result = operand1 + operand2
elif operator == '-':
result = operand1 - operand2
elif operator == '*':
result = operand1 * operand2
elif operator == '/':
result = operand1 / operand2
else:
raise ValueError("Invalid operator")
operand_stack.push(result)
def evaluate(expression):
operator_stack = Stack()
operand_stack = Stack()
for char in expression:
if char.isdigit():
operand_stack.push(int(char))
elif char in priority:
while (not operator_stack.is_empty() and
priority[char] <= priority[operator_stack.top()]):
apply_operator(operator_stack, operand_stack)
operator_stack.push(char)
elif char == '(':
operator_stack.push(char)
elif char == ')':
while (not operator_stack.is_empty() and
operator_stack.top() != '('):
apply_operator(operator_stack, operand_stack)
if operator_stack.is_empty():
raise ValueError("Invalid expression")
operator_stack.pop()
while not operator_stack.is_empty():
apply_operator(operator_stack, operand_stack)
return operand_stack.top()
return evaluate(expression)
# 测试表达式计算
expression = "(5*10+2-7+5)/10+5"
result = calculate_expression(expression)
print(f"Expression: {expression}")
print(f"Result: {result}")
运行以上代码,将会输出以下结果:
Expression: (5*10+2-7+5)/10+5
Result: 8.5
这段代码使用栈来模拟了表达式的计算过程。首先遍历表达式中的字符,如果是数字,则直接将其放入操作数栈;如果是操作符,则与操作符栈顶的操作符进行比较优先级,如果当前操作符的优先级小于等于栈顶操作符的优先级,则执行栈顶操作符与操作数的计算,并将结果放回操作数栈,直到优先级满足要求。遇到括号时,需要特殊处理。最后,当表达式遍历完毕后,计算剩余的操作符和操作数得到最终结果。
Java源码实现
import java.util.Stack;
public class ExpressionCalculator {
public static double calculateExpression(String expression) {
Stack<Double> operandStack = new Stack<>();
Stack<Character> operatorStack = new Stack<>();
for (int i = 0; i < expression.length(); i++) {
char ch = expression.charAt(i);
if (ch == ' ') {
continue; // 跳过空格
}
if (Character.isDigit(ch)) {
StringBuilder num = new StringBuilder();
while (i < expression.length() && (Character.isDigit(expression.charAt(i)) || expression.charAt(i) == '.')) {
num.append(expression.charAt(i++));
}
operandStack.push(Double.parseDouble(num.toString()));
i--; // 回退一位,因为在for循环中会自增
} else if (ch == '(') {
operatorStack.push(ch);
} else if (ch == ')') {
while (operatorStack.peek() != '(') {
performOperation(operandStack, operatorStack);
}
operatorStack.pop(); // 弹出左括号
} else if (isOperator(ch)) {
while (!operatorStack.isEmpty() && hasHigherPrecedence(ch, operatorStack.peek())) {
performOperation(operandStack, operatorStack);
}
operatorStack.push(ch);
}
}
while (!operatorStack.isEmpty()) {
performOperation(operandStack, operatorStack);
}
return operandStack.pop();
}
private static boolean isOperator(char ch) {
return ch == '+' || ch == '-' || ch == '*' || ch == '/';
}
private static boolean hasHigherPrecedence(char op1, char op2) {
if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) {
return true;
}
return false;
}
private static void performOperation(Stack<Double> operandStack, Stack<Character> operatorStack) {
double num2 = operandStack.pop();
double num1 = operandStack.pop();
char operator = operatorStack.pop();
double result = 0;
switch (operator) {
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
result = num1 / num2;
break;
}
operandStack.push(result);
}
public static void main(String[] args) {
String expression = "(5 * 10 + 2 - 7 + 5) / 10 + 5";
double result = calculateExpression(expression);
System.out.println("Result: " + result);
}
}
具体实现过程如下:
-
定义两个栈,一个用于存储操作数(operandStack),另一个用于存储运算符(operatorStack)。
-
遍历输入的表达式字符串中的每个字符,根据字符的不同类型执行不同的操作:
-
如果是数字,将其转换为整数并压入操作数栈中;
-
如果是左括号,将其压入运算符栈中;
-
如果是右括号,从运算符栈中弹出所有左括号,直到遇到左括号为止,然后对操作数栈中的元素进行计算,并将结果压入操作数栈中;
-
如果是运算符,从运算符栈中弹出一个运算符,如果该运算符的优先级高于当前运算符,则先对操作数栈中的元素进行计算,然后再进行当前运算符的计算;否则直接进行当前运算符的计算。最后将计算结果压入操作数栈中。
-
-
当运算符栈为空时,说明已经完成了所有的计算,此时从操作数栈中取出最后一个元素作为最终的结果。
-
在主函数中调用calculateExpression方法,传入一个表达式字符串作为参数,并输出计算结果。