思路
中缀表达式转后缀表达式
- 初始化两个栈,运算符栈s1和储存中间结果的栈s2
- 从左到右扫描中缀表达式
- 遇到数字则压入s2中
- 遇到运算符{
– 1.如果s1为空,或栈顶运算符为左括号,则直接将此运算符压入s1
– 2.若优先级比栈顶运算符高,也压入s1
– 3.否则,将栈顶的运算符弹出并压入s2中,再次转到 4.1 与s1中新的栈顶运算符比较
} - 遇到括号
{
–1. 如果是左括号,则直接压入s1
–2. 如果是右括号,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
} - 重复步骤2至5,直到表达式最右边
- 将s1中剩余的运算符依次弹出并压入s2
- 依次弹出s2的元素,结果的逆序即对应的后缀表达式。
计算后缀表达式
- 从左到右扫描表达式,遇到数字时,将数字压入栈中
- 遇到运算符时,弹出栈顶的两个数,用运算符对他们进行相应的运算并将结果入栈
- 重复上述过程,直到表达式最右端,得到的结果即后缀表达式的结果
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace InsufixToSuffix
{
class Program
{
static void Main(string[] args)
{
/*
* 完成将一个中缀表达式转成后缀表达式的功能
* 1. 目标 1+((2+3)*4)-5 => 1 2 3 + 4 * + 5 -
* 2. 因为对 string 进行操作不方便,因此先将表达式转换成对应的list
* 3.将得到的中缀表达式对应的 list 转换成 后缀表达式对应的list
*/
string expression = "1+((2+3)*4)-5";
List<string> infixExpression = ToInfixExpressionList(expression);
List<string> parseSuffixExpression = ParseSuffixExpressionList(infixExpression);
foreach (var item in parseSuffixExpression)
{
Console.Write(item + " ");
}
Console.WriteLine();
Console.WriteLine($"Res = {Calculate(parseSuffixExpression)}");
}
//将中缀表达式转换成对应的 List
static List<string> ToInfixExpressionList(string s)
{
//定义一个List,存放中缀表达式对应的内容
List<string> ls = new List<string>();
int i = 0; //用于遍历 中缀表达式字符串
string str; //用于对多位数的拼接
char c; //每遍历到一个字符,就放入c
do
{
if (!char.IsDigit(c = s[i])) //如果c不是数字,就加入ls
{
ls.Add(c.ToString());
i++; //i后移
}
else//如果是数字,需要考虑多位数
{
str = ""; //先将str清空
while (i < s.Length && char.IsDigit(c = s[i]))
{
str += c;
i++;
}
ls.Add(str);
}
} while (i < s.Length);
return ls;
}
//完成将一个中缀表达式转换成后缀表达式
static List<string> ParseSuffixExpressionList(List<string> ls)
{
//定义两个栈
Stack<string> s1 = new Stack<string>();
//因为 s2 在整个转换操作中没有pop操作,而且最后还要逆序,因此使用 List
List<string> s2 = new List<string>();
//遍历 ls
foreach (var item in ls)
{
Regex regex = new Regex("\\d+");
//如果是一个数,则加入s2
if (regex.Match(item).Length > 0)
{
s2.Add(item);
}
else if (item.Equals("("))
{
s1.Push(item);
}
else if (item.Equals(")"))
{
//如果是右括号,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,并将这对括号丢弃
while (!s1.Peek().Equals("("))
{
s2.Add(s1.Pop());
}
s1.Pop(); //将 ( 弹出
}
else
{
//当item 的 优先级小于或等于s1栈顶运算符,将s1栈顶的运算符弹出并加入到s2中,再次转到 4.1 与s1中新的栈顶运算符比较
while (s1.Count != 0 && SomeMethods.GetValue(s1.Peek()) >= SomeMethods.GetValue(item))
{
s2.Add(s1.Pop());
}
//还需要将 item 压入栈
s1.Push(item);
}
}
//将s1中剩余的运算符依次弹出并加入s2
while (s1.Count != 0)
{
s2.Add(s1.Pop());
}
return s2; //因为时存放到 List,因此按顺序输出就是对应的后缀表达式对应的List
}
//计算逆波兰表达式
static int Calculate(List<string> ls)
{
Regex regex = new Regex("\\d+");
//创建栈
Stack<string> stack = new Stack<string>();
//遍历 list
foreach (var item in ls)
{
//使用正则表达式来取出数
if (regex.Match(item).Length > 0) //如果是数字,就压入栈中
{
stack.Push(regex.Match(item).Value);
}
else //不是数就弹出两个数字进行计算
{
int num2 = int.Parse(stack.Pop());
int num1 = int.Parse(stack.Pop());
int res = 0;
if (item.Equals("+"))
{
res = num1 + num2;
}
else if (item.Equals("-"))
{
res = num1 - num2;
}
else if (item.Equals("*"))
{
res = num1 * num2;
}
else if (item.Equals("/"))
{
res = num1 / num2;
}
else
{
throw new Exception("表达式有误");
}
stack.Push(res.ToString());
}
}
//最后留在stack中的数据就是运算结果
return int.Parse(stack.Pop());
}
}
class SomeMethods
{
private static int ADD = 1;
private static int SUB = 1;
private static int MUL = 2;
private static int DIV = 2;
//返回优先级
public static int GetValue(string operation)
{
int res = 0;
switch (operation)
{
case "+":
res = ADD;
break;
case "-":
res = SUB;
break;
case "*":
res = MUL;
break;
case "/":
res = DIV;
break;
default:
Console.WriteLine("不存在该运算符");
break;
}
return res;
}
}
}