数据结构学习-后缀表达式计算
最近在学习程杰老师的《大话数据结构》,当读到栈那一节部分内容的时候,发现了一个很有趣的计算四则运算的方式:后缀表达式计算法,也叫作逆波兰式。是一种将运算符写在数字后面的一种表达式写法。
例如:9+(3-1)3+10/2,化为逆波兰式就是:931-3+102/+
我就尝试着用C#实现了一下,代码如下:
ps.大佬勿喷,我就是想体验一下这种写法,如果觉得我是在用高级语言做无用功,那就无用吧= =。
static void Main(string[] args)
{
Console.WriteLine("请输入想要计算的复杂计算式");
string inputStr = Console.ReadLine();
if (string.IsNullOrWhiteSpace(inputStr))
{
Console.WriteLine("您没有输入任何表达式");
return;
}
//获取后缀表达式
var suffixStr = GetSuffixStr(inputStr);
Console.WriteLine("后缀表达式为:" + suffixStr);
//根据后缀表达式计算结果
var result = GetResult(suffixStr);
Console.WriteLine("计算结果为:" + result);
Console.ReadKey();
}
/// <summary>
/// 获取后缀表达式
/// </summary>
/// <param name="expression">中缀表达式</param>
/// <returns></returns>
public static string GetSuffixStr(string expression)
{
Stack<char> stack = new Stack<char>();
//将中文算数操作符转换成英文操作符
expression = ToDBC(expression);
string suffixStr = string.Empty;
foreach (char c in expression)
{
//如果是数字,则放置到结果字符串中
if (char.IsDigit(c))
{
suffixStr += c;
continue;
}
//如果是右括号 => 出栈
if (c == ')')
{
//循环出栈,直至遇到'('
while (stack.Peek() != '(')
{
suffixStr += stack.Pop();
}
//最后需要将对应的'('也出栈
stack.Pop();
}
//如果优先级小于栈顶元素 => 出栈
else if (stack.Count != 0 && SetPriority(stack.Peek()) > SetPriority(c) && stack.Peek() != '(')
{
//循环出栈,直至遇到'('或者全部出栈
while (stack.Count != 0 && stack.Peek() != '(')
{
suffixStr += stack.Pop();
}
}
else //否则直接进栈
{
stack.Push(c);
}
}
//字符串循环完毕,栈中剩余操作符依次出栈
while (stack.Count != 0)
{
suffixStr += stack.Pop();
}
return suffixStr;
}
/// <summary>
/// 获取计算结果
/// </summary>
/// <param name="suffixStr">后缀表达式</param>
/// <returns></returns>
public static int GetResult(string suffixStr)
{
Stack<int> stack = new Stack<int>();
foreach (char c in suffixStr)
{
//如果是数字,则进栈
if (char.IsDigit(c))
{
stack.Push(Convert.ToInt32(c.ToString()));
continue;
}
//如果不是数字,则取前两位出栈进行相应计算,将结果入栈
else
{
var num1 = stack.Pop();
var num2 = stack.Pop();
switch (c)
{
case '+':
stack.Push(num2 + num1);
break;
case '-':
stack.Push(num2 - num1);
break;
case '*':
stack.Push(num2 * num1);
break;
case '/':
stack.Push(num2 / num1);
break;
}
}
}
return stack.Pop();
}
/// <summary>
/// 全角字符转半角
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static string ToDBC(string input)
{
input = input.Trim();
char[] c = input.ToCharArray();
for (int i = 0; i < c.Length; i++)
{
if (c[i] == 12288)
{
c[i] = (char)32; continue;
}
if (c[i] > 65280 && c[i] < 65375)
c[i] = (char)(c[i] - 65248);
}
return new string(c);
}
/// <summary>
/// 设置优先级
/// </summary>
/// <param name="symbol">运算符</param>
/// <returns></returns>
public static int SetPriority(char symbol)
{
int level = default(int);
switch (symbol)
{
case '+':
level = 1;
break;
case '-':
level = 1;
break;
case '*':
level = 2;
break;
case '/':
level = 2;
break;
case '(':
level = 9;
break;
case ')':
level = 9;
break;
}
return level;
}
运行结果为:
关于这个方法还有很多不足之处,比如现在只是允许10以下的数字运算,还有优先级的判断也不完善,欢迎各位大佬指正!