字符串表达式求值(转)
算术表达式中最常见的表示法形式有 中缀、前缀和 后缀表示法。中缀表示法是书写表达式的常见方式,而前缀和后缀表示法主要用于计算机科学领域。
中缀表示法
中缀表示法是算术表达式的常规表示法。称它为 中缀表示法是因为每个操作符都位于其操作数的中间,这种表示法只适用于操作符恰好对应两个操作数的时候(在操作符是二元操作符如加、减、乘、除以及取模的情况下)。对以中缀表示法书写的表达式进行语法分析时,需要用括号和优先规则排除多义性。
Syntax: operand1 operator operand2Example: (A+B)*C-D/(E+F) |
前缀表示法
前缀表示法中,操作符写在操作数的前面。这种表示法经常用于计算机科学,特别是编译器设计方面。为纪念其发明家 ― Jan Lukasiewicz(请参阅 参考资料),这种表示法也称 波兰表示法。
Syntax : operator operand1 operand2Example : -*+ABC/D+EF |
后缀表示法
在后缀表示法中,操作符位于操作数后面。后缀表示法也称 逆波兰表示法(reverse Polish notation,RPN),因其使表达式求值变得轻松,所以被普遍使用。
Syntax : operand1 operand2 operatorExample : AB+C*DEF+/- |
前缀和后缀表示法有三项公共特征:
- 操作数的顺序与等价的中缀表达式中操作数的顺序一致
- 不需要括号
- 操作符的优先级不相关
要把表达式从中缀表达式的形式转换成用后缀表示法表示的等价表达式,必须了解操作符的优先级和结合性。 优先级或者说操作符的强度决定求值顺序;优先级高的操作符比优先级低的操作符先求值。 如果所有操作符优先级一样,那么求值顺序就取决于它们的 结合性。操作符的结合性定义了相同优先级操作符组合的顺序(从右至左或从左至右)。
Left associativity : A+B+C = (A+B)+CRight associativity : A^B^C = A^(B^C) |
转换过程包括用下面的算法读入中缀表达式的操作数、操作符和括号:
- 初始化一个空堆栈,将结果字符串变量置空。
- 从左到右读入中缀表达式,每次一个字符。
- 如果字符是操作数,将它添加到结果字符串。
- 如果字符是个操作符,弹出(pop)操作符,直至遇见开括号(opening parenthesis)、优先级较低的操作符或者同一优先级的右结合符号。把这个操作符压入(push)堆栈。
- 如果字符是个开括号,把它压入堆栈。
- 如果字符是个闭括号(closing parenthesis),在遇见开括号前,弹出所有操作符,然后把它们添加到结果字符串。
- 如果到达输入字符串的末尾,弹出所有操作符并添加到结果字符串。
对后缀表达式求值比直接对中缀表达式求值简单。在后缀表达式中,不需要括号,而且操作符的优先级也不再起作用了。您可以用如下算法对后缀表达式求值:
- 初始化一个空堆栈
- 从左到右读入后缀表达式
- 如果字符是一个操作数,把它压入堆栈。
- 如果字符是个操作符,弹出两个操作数,执行恰当操作,然后把结果压入堆栈。如果您不能够弹出两个操作数,后缀表达式的语法就不正确。
- 到后缀表达式末尾,从堆栈中弹出结果。若后缀表达式格式正确,那么堆栈应该为空。

#region 中缀转后缀
/// <summary>
/// 中缀表达式转换为后缀表达式
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
public static string InfixToPostfix(string expression)
{
Stack<char> operators = new Stack<char>();
StringBuilder result = new StringBuilder();
for (int i = 0; i < expression.Length; i++)
{
char ch = expression[i];
if (char.IsWhiteSpace(ch)) continue;
switch (ch)
{
case '+':
case '-':
while (operators.Count > 0)
{
char c = operators.Pop(); //pop Operator
if (c == '(')
{
operators.Push(c); //push Operator
break;
}
else
{
result.Append(c);
}
}
operators.Push(ch);
result.Append(" ");
break;
case '*':
case '/':
while (operators.Count > 0)
{
char c = operators.Pop();
if (c == '(')
{
operators.Push(c);
break;
}
else
{
if (c == '+' || c == '-')
{
operators.Push(c);
break;
}
else
{
result.Append(c);
}
}
}
operators.Push(ch);
result.Append(" ");
break;
case '(':
operators.Push(ch);
break;
case ')':
while (operators.Count > 0)
{
char c = operators.Pop();
if (c == '(')
{
break;
}
else
{
result.Append(c);
}
}
break;
default:
result.Append(ch);
break;
}
}
while (operators.Count > 0)
{
result.Append(operators.Pop()); //pop All Operator
}
return result.ToString();
}
#endregion
#region 求值经典算法
/// <summary>
/// 求值的经典算法
/// </summary>
/// <param name="expression">字符串表达式</param>
/// <returns></returns>
public static double Parse(string expression)
{
string postfixExpression = InfixToPostfix(expression);
Stack<double> results = new Stack<double>();
double x, y;
for (int i = 0; i < postfixExpression.Length; i++)
{
char ch = postfixExpression[i];
if (char.IsWhiteSpace(ch)) continue;
switch (ch)
{
case '+':
y = results.Pop();
x = results.Pop();
results.Push(x + y);
break;
case '-':
y = results.Pop();
x = results.Pop();
results.Push(x - y);
break;
case '*':
y = results.Pop();
x = results.Pop();
results.Push(x * y);
break;
case '/':
y = results.Pop();
x = results.Pop();
results.Push(x / y);
break;
default:
int pos = i;
StringBuilder operand = new StringBuilder();
do
{
operand.Append(postfixExpression[pos]);
pos++;
} while (char.IsDigit(postfixExpression[pos]) || postfixExpression[pos] == '.');
i = --pos;
results.Push(double.Parse(operand.ToString()));
break;
}
}
return results.Peek();
}
#endregion
———————————————————————————————————
浩瀚的天空,会有改变的希望,世界会不会变得更加好,选择在於我们的手上。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义