目录
一、前缀中缀后缀表达式
1.中缀表达式
中缀表达式就是平常生活中计算式子的写法,例如:(3+4)*5-6 就是一个中缀表达式
2.前缀表达式
1)前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前
2)要想知道前缀表达式怎么写,需要先了解前缀表达式在计算机中是怎样求值的:从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们进行相应的计算,并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果。
( 3 + 4 )* 5 - 6 的前缀表达式为 - * + 3 4 5 6
3.后缀表达式
1)后缀表达式又称逆波兰表达式,运算符位于操作数之后
2)后缀表达式在计算机中时怎么求值的:从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们进行相应的计算,并将结果入栈;重复上述过程直到表达式最右端,最后算出的值即为表达式结果。
( 3 + 4 )* 5 - 6 的后缀表达式为 3 4 + 5 * 6 -
二、中缀转后缀
这里直接说过程,不解释原理了,会用就行。
中缀转后缀过程:
1.初始化两个栈:运算符栈s1和储存中间结果栈s2
2.从左至右扫描中缀表达式
3.遇到数字时,直接压入s2
4.遇到运算符时:
1)如果s1为空,或者栈顶为“(”,直接把遇到的运算符压入s1
2)若遇到的运算符比栈顶的运算符优先级高,直接把遇到的运算符压入s1
3)如果栈顶运算符的优先级大于等于遇到运算符的优先级,则把栈顶的运算符弹出并压入s2,然后继续让遇到的运算符和s1中新的栈顶运算符比较,直到遇到的运算符压入s1为止
5.遇到括号时:
1)如果遇到左括号“( ”,直接压入s1
2)如果遇到右括号“ )”,则把s1中最上面的左括号的上面的所有运算符依次弹出并压入s2,然后把这一对括号给清除,也就是把左括号给删了
6.重复步骤2-5,直到表达式最右边
7.将s1中剩余的运算符依次弹出并压入s2
8.此时s2中的顺序为后缀表达式,但依次弹出后为后缀表达式的逆序,所以把s2里面的东西依次弹出后,还需要逆序一下,就是后缀表达式了
但是,在实际写代码过程中,可以灵活运用这个思路,我们其实初始化一个栈就可以了,另外一个栈可以用集合替代,具体看代码:
using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
namespace _8.中缀转后缀
{
class Program
{
static void Main(string[] args)
{
//测试
string a = "1+((2+3)*4)-5";
List<string> b = toInfixExpressionList(a);
List<string> c = paresSuffixExpreesionList(b);
foreach (var item in c)
{
Console.Write(item);
}
}
//中缀转后缀
public static List<string> paresSuffixExpreesionList(List<string> ls)
{
Stack<string> s1 = new Stack<string>();
List<string> s2 = new List<string>();
foreach (var item in ls)
{
if(IsInt(item))
{
s2.Add(item);
}
else if(item == "(")
{
s1.Push(item);
}
else if(item == ")")
{
while(s1.Peek() != "(")
{
s2.Add(s1.Pop());
}
s1.Pop();
}
else
{
while(s1.Count != 0 && getValue(s1.Peek())>=getValue(item)&&s1.Peek() != "(")
{
s2.Add(s1.Pop());
}
s1.Push(item);
}
}
while(s1.Count!=0)
{
s2.Add(s1.Pop());
}
return s2;
}
//返回优先级,数字越大优先级越高
public static int getValue(string operation)
{
switch(operation)
{
case "+":
return 1;
case "-":
return 1;
case "*":
return 2;
case "/":
return 2;
default:
return 0;
}
}
//判断是否为正整数
public static bool IsInt(string inString)
{
Regex regex = new Regex("^\\d+$");
return regex.IsMatch(inString.Trim());
}
//输入的string放入集合里
public static List<string> toInfixExpressionList(string s)
{
List<string> ls = new List<string>();
int i = 0;//用于遍历
string str = "";//对多位数拼接
char c;//遍历到字符放入c
while(i<s.Length)
{
c = s[i];
if(c<'0'||c>'9')
{
ls.Add(c.ToString());
i++;
}
else
{
while(i<s.Length&&s[i]>='0'&&s[i]<='9')
{
c = s[i];
str += c;
i++;
}
ls.Add(str);
str = "";
}
}
return ls;
}
}
}
把string变成list(集合)容易操作。
为什么用一个栈就行:理解的时候用两个栈更好理解,实际写代码过程中,只需要初始化一个栈(s1)和一个集合(s2),那为什么另一个栈(s2)变成集合更好,因为变成集合后,就可以不用逆序就是最后的后缀表达式(可以直接用),如果s2用栈的话,最后弹出后,还需要再逆序一下才为后缀表达式。