背景
大话数据结构4.9栈的应用——四则运算表达式求值,动手实践。
步骤
1.将中缀表达式转换为后缀表达式(参考 中缀表达式转换为后缀表达式)
- 定义
标准四则运算表达式叫做中缀表达式,特点是运算符号都在
- 规则
- 从左到右遍历表达式的每个数字和符号
- 若是数字就输出
- 若是符号,判断该符号与栈顶符号的优先级。
当前符号优先级 > 栈顶符号时, 进栈。
当前符号优先级 <= 栈顶符号,栈顶元素依次出栈、输出,当前符号进栈。
当前符号是右括号,栈顶元素依次出栈并输出,直到遇到左括号停止,左括号弹出但不输出。
2.使用后缀表达式进行运算,得出结果
- 规则
- 从左到右遍历表达式的每个数字和符号
- 遇到数字就进栈,遇到符号就将处于栈顶的两个数字出栈运算,运算结果进栈。
代码
ExpressionsHelper.cs文件
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace DataStructure
{
/// <summary>
/// 栈的应用-计算四则表达式
/// 1、将中缀表达式转换成后缀表达式
/// 2、使用后缀表达式进行运算,得出结果
/// </summary>
class ExpressionsHelper
{
private static int GetPriority(string op)
{
switch (op)
{
case "+":
case "-":
return 1;
case "*":
case "/":
return 2;
case "":
return 3;
}
return -1;
}
/// <summary>
/// 将中缀表达式转换成后缀表达式
/// 标准四则运算表达式->中缀表达式:所有运算负号都在两数字中间
/// 1、从左到右遍历中缀表达式的每个数字和符号
/// 2、是数字就输出,是符号则判断与栈顶符号的优先级,
/// 3、当前符号优先级<=栈顶符号或者当前符号是右括号,栈顶元素依次出栈,将当前符号进栈
/// 4、遇到右括号才弹出左括号
/// 测试用例:9 + ( 3 - 1 ) * 3 + 10 / 2 期望结果:9 3 1 - 3 * + 10 2 / +
/// 测试用例:1 + 2 * 3 + ( 4 * 5 + 6 ) * 7 期望结果:1 2 3 * + 4 5 * 6 + 7 * +
/// 测试用例:10*(0.8+0.2) 期望结果:10 0.8 0.2 + *
/// </summary>
public static string GetPostfixExpression(string infixExpression)
{
Stack<string> tmpStack = new Stack<string>();
List<string> resultList = new List<string>();
List<string> tmp = new List<string>();
//提取+-*/数字和括号
foreach (Match match in Regex.Matches(infixExpression, @"([+\-*/\(\)])|(\d+(\.\d+)?)"))
tmp.Add(match.Value);
foreach (var item in tmp)
{
if (item == "")
{
continue;
}
if (IsNumberic(item))//数字输出
{
resultList.Add(item);
}
else if (item == "(")
{
tmpStack.Push(item);
}
else if (item == ")")
{
while (tmpStack.Count > 0 && tmpStack.Peek() != "(")
{
var top = tmpStack.Pop();
resultList.Add(top);
}
//只有遇到右括号的时候左括号才会弹出
if (tmpStack.Count > 0 && tmpStack.Peek() == "(")
{
tmpStack.Pop();
}
}
else
{
//优先级:当前<=栈顶,当前符号优先级低于或等于栈顶符号,栈顶元素依次出栈,将当前符号进栈,遇到左扩号停止弹出行为。
while (tmpStack.Count > 0 && GetPriority(item) <= GetPriority(tmpStack.Peek()))
{
var top = tmpStack.Pop();
resultList.Add(top);
}
tmpStack.Push(item);
}
}
//数据已经读到末尾,栈中符号直接弹出并输出
while (tmpStack.Count != 0)
{
var top = tmpStack.Pop();
resultList.Add(top);
}
//空格分隔
var result = string.Join(" ", resultList);
Console.WriteLine($"中缀表达式:{infixExpression}");
Console.WriteLine($"后缀表达式:{result}");
return result;
}
/// <summary>
/// 使用后缀表达式进行运算,得出结果(每个输入都要用空格分隔)
/// 规则
/// 1、从左到右遍历表达式的每个数字和符号
/// 2、遇到数字就进栈,遇到符号就将处于栈顶的两个数字出栈运算,运算结果进栈。
/// </summary>
public static float GetPostfixExpressionResult(string postfixExpression)
{
Stack<float> tmpStack = new Stack<float>();
string[] tmp = Regex.Split(postfixExpression, "\\s+", RegexOptions.IgnoreCase);
foreach (var item in tmp)
{
if (IsNumberic(item))
{
if (int.TryParse(item, out int intItem))
{
tmpStack.Push(intItem);
}
else if (float.TryParse(item, out float floatItem))
{
tmpStack.Push(floatItem);
}
}
else
{
var b = tmpStack.Pop();
var a = tmpStack.Pop();
var tmpResult = GetResult(a, item, b);
tmpStack.Push(tmpResult);
}
}
var result = tmpStack.Pop();
if (tmpStack.Count > 0)
{
throw new Exception("后缀表达式错误");
}
Console.WriteLine($"运算结果:{result}");
return result;
}
/// <summary>
/// 计算中缀表达式
/// </summary>
public static float Calc(string infixExpression)
{
var postfixExpression = GetPostfixExpression(infixExpression);
var result = GetPostfixExpressionResult(postfixExpression);
return result;
}
private static float GetResult(float a, string symbol, float b)
{
float result = 0;
switch (symbol)
{
case "+":
result = a + b;
break;
case "-":
result = a - b;
break;
case "*":
result = a * b;
break;
case "/":
result = a / b;
break;
default:
break;
}
return result;
}
/// <summary>
/// 判断是否数字
/// </summary>
public static bool IsNumberic(string num)
{
string pattern = @"\d+(\.\d+)?"; //匹配整数和浮点数
bool result = Regex.IsMatch(num, pattern);
return result;
}
}
}
Program.cs文件
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataStructure
{
class Program
{
static void Main(string[] args)
{
#region 栈的应用 - 计算四则表达式(整数公式)
var v1 = ExpressionsHelper.Calc("9+(3-1)*3+10/2");
Console.WriteLine();
var v2 = ExpressionsHelper.Calc("1+2*3+(4*5+6)*7");
Console.WriteLine();
#endregion
#region 栈的应用 - 计算四则表达式(浮点数公式)
var v3 = ExpressionsHelper.Calc("10*(0.8+0.2)");
Console.WriteLine();
var v4 = ExpressionsHelper.Calc("10*(8+2)");
Console.WriteLine();
#endregion
}
}
}
结果
完整项目
https://github.com/LJLCarrien/DataStructure
后续
上面贴的代码已更新,在原来的基础上,支持浮点数表达式运算;