/*
1)遇到操作数,直接输出
2)遇到左括号,进栈
3)遇到右括号,逐个将括号内元素出栈并输出,最后弹出左括号
4)遇到运算符,从栈中弹出元素并输出直到遇到发现更低优先级的元素(或者栈为空)为止,再将遇到的运算符入栈
5)最后栈中所有元素依次弹出并输出
*/
/// <summary>
/// 逆波兰计算器
/// </summary>
static class RPNCalculator
{
/// <summary>
/// 逆波兰计算器
/// </summary>
/// <param name="ls">中缀表达式</param>
/// <returns>运算结果</returns>
public static double Start(List<string> ls)=>GetValue(Transform(ls));
/// <summary>
/// 获取运算符优先级
/// </summary>
/// <param name="str">运算符串</param>
/// <returns>优先级</returns>
private static int GetPriorLevel(string str)
{
switch (str\[0\])
{
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '^':
return 3;
default:
return 0;
}
}
/// <summary>
/// 二元运算
/// </summary>
/// <param name="op">运算符</param>
/// <param name="x">第一个数</param>
/// <param name="y">第二个树</param>
/// <returns>运算结果</returns>
private static double Calculate(string op,double x, double y)
{
switch (op)
{
case "+":
return y+x;
case "-":
return y-x;
case "*":
return y*x;
case "/":
return y/x;
case "^":
return Math.Pow(y, x);
default:
return 0;
}
}
/// <summary>
/// 是否是数字
/// </summary>
/// <param name="str">字符串</param>
/// <returns>布尔值</returns>
private static bool IsNum(string str) => Regex.IsMatch(str, @"^(-?\\d+)(\\.\\d+)?$");
/// <summary>
/// 逆波兰转换
/// </summary>
/// <param name="str">中缀表达式</param>
/// <returns>逆波兰式</returns>
private static List<string> Transform(List<string> ls)
{
#if TEST
foreach (var item in ls)
Write(item + " ");
WriteLine();
#endif
//存放转换结果
List<string> ans = new List<string>();
//栈
SQStack<string> sk = new SQStack<string>();
for(int i=0;i<ls.Count;++i)
{
var item = ls\[i\].Trim();
//如果是数字,直接输出
if (IsNum(item))
ans.Add(item);
//如果是"(",进栈
else if (item == "(")
sk.Push(item);
//如果是")",括号内的元素出栈并输出
else if (item == ")")
{
while (sk.GetTop() != "(")
ans.Add(sk.Pop());
sk.Pop();//并将"("出栈
}
//其他运算符的情况
else
{
//栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)为止
while (!sk.IsEmpty() && GetPriorLevel(sk.GetTop()) > GetPriorLevel(item))
ls.Add(sk.Pop());
sk.Push(item);//运算符入栈
}
}
//输入末尾,所有元素依次弹出
while (!sk.IsEmpty())
ans.Add(sk.Pop());
return ans;
}
/// <summary>
/// 逆波兰求值
/// </summary>
/// <param name="ls">逆波兰式</param>
/// <returns>运算结果</returns>
private static double GetValue(List<string> ls)
{
#if TEST
foreach (var item in ls)
Write(item + " ");
WriteLine();
#endif
SQStack<double> sk = new SQStack<double>();
foreach (var item in ls)
{
//遇到数字就进栈
if(IsNum(item))
sk.Push(double.Parse(item));
else//否则遇到符号,出栈两个数字并运算
sk.Push(Calculate(item, sk.Pop(), sk.Pop()));//运算结果进栈
}
return sk.Pop();
}
}