# 逆波兰表达式

形如 12+3*12+4/- ,后缀表达式,方便计算机进行运算

# 计算 RPN

  1. 需要一个堆栈,用于存放数字
  2. 从左到右读取表达式
  3. 碰到数字则将数字压入堆栈,碰到运算符则将堆栈内的数字取出两个,先弹出的放在运算符右侧,后弹出的放在运算符左侧,执行计算后将结果再次压入堆栈
  4. 直至字符串读取完毕,此时将堆栈内的数字弹出,即为最终的结果

使用 12+3*12+4/- 举例:

步骤待处理元素数字堆栈运算
111
2212
3+31+2
4333
5*93*3
6191
72912
8+931+2
94934
10/9(0.75)3/4
11-8.259-0.75

# 示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public static double CalcRPN(string RPN)
{
Stack<double> nums = new Stack<double>();
StringBuilder numSu = new StringBuilder();
RPN = ReplaceUnleagalChar(RPN);
bool flag = false;
for (int i = 0; i < RPN.Length; i++)
{
if (char.IsDigit(RPN[i]) || RPN[i] == '.' || (i > 0 && RPN[i - 1] == '('))
{
if (flag)
{
numSu.Append(RPN[i]);
continue;
}
nums.Push(RPN[i] - '0');
}
else
{
if (RPN[i] != '(' && !string.IsNullOrWhiteSpace(numSu.ToString()))
{
nums.Push(double.Parse(numSu.ToString()));
numSu.Clear();
flag = false;
continue;
}
if (RPN[i] == '(' || RPN[i] == ')')
{
flag = true;
continue;
}
double OPb = nums.Pop();
double OPa = nums.Pop();
switch (RPN[i])
{
case '+':
nums.Push(OPa + OPb);
break;
case '-':
nums.Push(OPa - OPb);
break;
case '*':
nums.Push(OPa * OPb);
break;
case '/':
nums.Push(OPa / OPb);
break;
default:
break;
}
numSu.Clear();
}
}
return nums.Pop();
}

# 中缀表达式转后缀表达式

  1. 需要一个堆栈,用于存放运算符
  2. 从左到右读取中缀表达式
  3. 碰到数字则将数字输出,碰到运算符则需要进行判断:
    1. 运算符堆栈内是否有值,若没有则压入堆栈
    2. 若有值,则需要判断栈顶元素与运算符的优先级,例如 ( > * * > + ,若大于则压入栈,否则将栈顶元素弹出栈输出到结果,直至运算符优先级大于等于栈顶元素 (碰到 ( 则不继续弹出)
    3. 若为 ) ,则一直弹出栈顶元素输出到结果,直至碰到 ( ,此时舍弃 (

使用 (1+2)*3-(1+2)/4 举例:

步骤待处理元素结果运算符堆栈
1((
211(
3+1(+
4212(+
5)12+
6*12+*
7312+3*
8-12+3*-
9(12+3*-(
10112+3*1-(
11+12+3*1-(+
12212+3*12-(+
13)12+3*12+-
14/12+3*12+-/
15412+3*12+4-/
16end12+3*12+4/-

# 示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public static string ParseToRPN(string pattern)
{
StringBuilder Rexpression = new StringBuilder();

pattern = ReplaceUnleagalChar(pattern);
Stack<double> num = new Stack<double>();
Stack<char> oper = new Stack<char>();
StringBuilder stringBuilder = new StringBuilder();
bool flag = false;
for (int i = 0; i < pattern.Length; i++)
{
if (char.IsDigit(pattern[i]) || pattern[i] == '.' || (i == 0 && pattern[i] == '-') || (i > 0 && pattern[i - 1] == '('))
{
stringBuilder.Append(pattern[i]);
}
else
{
if (!string.IsNullOrWhiteSpace(stringBuilder.ToString()))
num.Push(double.Parse(stringBuilder.ToString()));
if (stringBuilder.Length > 1)
{
Rexpression.Append($"({stringBuilder})");
}
else
Rexpression.Append(stringBuilder.ToString());
stringBuilder.Clear();
flag = pattern[i] == '(';
PushOperators(ref oper, ref Rexpression, pattern[i]);
}
}
if (!string.IsNullOrWhiteSpace(stringBuilder.ToString()))
{
if (stringBuilder.Length > 1)
Rexpression.Append($"({stringBuilder})");
else
Rexpression.Append(stringBuilder.ToString());
}
while (oper.Count > 0)
Rexpression.Append(oper.Pop());
Console.WriteLine($"逆波兰表达式:{Rexpression}");
return Rexpression.ToString();
}
public static string ReplaceUnleagalChar(string p)
{
return p.Replace("(", "(").Replace(")", ")").Replace("÷", "/").Replace("×", "*")
.Replace("x", "*").Replace("除以", "/").Replace("除", "/").Replace("乘以", "*").Replace("乘", "*").Replace(" ", "");
}
public static void PushOperators(ref Stack<char> opers, ref StringBuilder Rexpression, char oper)
{
if (opers.Count == 0)
opers.Push(oper);
else if (oper == ')')
{
while (opers.Count != 0 && opers.Peek() != '(')
Rexpression.Append(opers.Pop());
opers.Pop();
}
else if (operators[oper] > operators[opers.Peek()])
opers.Push(oper);
else
{
while (opers.Count != 0 && opers.Peek() != '(' && operators[oper] <= operators[opers.Peek()])
Rexpression.Append(opers.Pop());
opers.Push(oper);
}
}
更新于 阅读次数