中缀到后缀(反向波兰表示法)的转换工作与括号,但不能没有
本文关键字:工作 转换 但不能 后缀 表示 中缀 | 更新日期: 2023-09-27 18:16:09
分配规则:
- 必须有单独的Operator类和单独的PostFix类包含转换方法。
- 从左到右求值 操作符被放置到Stack中。
- 仅限二进制操作符
- 分离Operator类和PostFix类,其中PostFix包含Conversion方法。c#
我的问题:
如果所有/大部分方程在括号中,我的转换工作。只有当输入符合操作顺序时,它才不需要括号。
我相信我只是没有正确检查优先级,但我不确定这是问题所在。我现在已经重写了我的转换方法4次,花了大约25个小时来调整和运行调试器上的不同迭代方法,并在谷歌上搜索,但我只是不明白问题在我的代码中。我在调试时看到了它,但我不确定我必须做些什么来修复它,所以我想也许第三方的观点会有所帮助。
例子错误输出:
a=5+3/4-(9*8-1)*1 => a 5 3 + 4 / 9 8 * 1 - - 1 * =
should be a 5 3 4 / + 9 8 * 1 - - 1 * =
alpha = beta + gamma * delta => alpha beta gamma + delta * =
should be alpha beta gamma delta * + =
正确的输出:
a = ((((a+b)-c)*d)/(e+1)) => a a b + c - d * e 1 + / =
alpha = beta * gamma + delta => beta gamma * delta + alpha =
我的代码操作符类:
class Operator
{
private byte precedence = 1; //Precedence of operator over others
private char identity = 'x'; //the character behind the operator
/// <summary>
/// Creates an operator based on the passed character
/// </summary>
/// <param name="OperatorIn">Character definition of the operator</param>
public Operator(char OperatorIn)
{
identity = OperatorIn;
switch (OperatorIn)
{
case '*':
precedence = 2;
break;
case '/':
precedence = 2;
break;
case '(':
precedence = 3;
break;
case ')':
precedence = 3;
break;
case '=':
precedence = 3;
break;
case '+':
precedence = 1;
break;
case '-':
precedence = 1;
break;
default:
precedence = 0;
break;
}//switch
}//Operator(char)
/// <summary>
/// Retrieves the char representation of the operator
/// </summary>
/// <returns>Char representation of the operator</returns>
public char ToChar()
{
return this.identity;
}//ToChar()
/// <summary>
/// Returns the byte value of precedence of the operator
/// </summary>
/// <returns>byte value of precedence</returns>
public byte GetPrecedence()
{
return this.precedence;
}
}//Operator
转换方法:
public static string Convert(string infix)
{
#region original
Stack<Operator> OpStack = new Stack<Operator>();
String Postfix = String.Empty;
InfixPostfix.Operator Previous = new Operator('x'),
Current = null; //NextOp = new Operator(infix[infix.IndexOfAny(Ops, i)]);
char[] Ops = {'+','-','=','*','/'};
string term = String.Empty;
foreach(char c in infix)
{
if (Ops.Contains(c)) //if the char is one of the operator chars
{
Postfix += term + " "; //split term and add to output
while (OpStack.Count > 0) //While there's actually operators in the stack
{
Current = OpStack.Pop(); //Assign the operator as Current Operator
if (Current.GetPrecedence() < Previous.GetPrecedence()) //If Current Op is less priority than preceding Op
Postfix += Current.ToChar() + " "; //Output the character of the Op
else //If Current Op priority is higher than the previous
{
Previous = Current; //Store the current as previous to move on
OpStack.Push(Current); //Store current in stack
break; //Move to next char
}//else
}//while
OpStack.Push(new Operator(c)); //If stack is empty, push the operator
term = ""; // and reset the term to empty
}//if
else if (c == ')') //If the char is a close paren
{
Postfix += term + " "; //store the previous characters as a term in postfix
term = ""; //establish a new term
Previous = Current; //Set Current as the old Op
Current = OpStack.Pop(); //Get the new Current op
while (Current.ToChar() != '(') //Pop the stack until you get an open paren op
{
Postfix += Current.ToChar() + " "; //Add the term to the output string
//Previous = Current;
try
{
Current = OpStack.Pop(); //Try to pop another operator
}//try
catch(Exception) //If the stack is empty
{
return "Error! Mismatched parentheses!"; //Then there is a missing/misaligned paren
}//catch
}//while
}//else if
else if (c == '(') //If the op is an open paren
OpStack.Push(new Operator(c)); //store it
else if (c != ' ') //If it's an alphanumeric char,
term += c; //build a term with it
}//foreach
Postfix += term + " "; //add the last term to the output
while(OpStack.Count > 0) //If there are remaining ops on the stack,
{
Current = OpStack.Pop(); //pop them off
if (Current.ToChar() == '(' || Current.ToChar() == ')') //If there is a paren remaining
return "Error! Mismatched parentheses!"; // it's because of missing complement or misalignment
Postfix += Current.ToChar() + " "; //if regular op, add to output
}//while
return Postfix;
}
提前感谢!
好的,我得到了一些赞,表明有人对这个答案感兴趣。我的解决办法是再次扔掉我拥有的东西,重新开始。我坐下来,在纸上多次检查算法,然后一次调试一行。这导致了一些"有趣"的调整,只是为了完成这一点。
老实说,我想到的东西很恶心——在某一点上,我有一个for-else if-if-if-while-if。所以这个东西不好看,而且可能效率很低。幸运的是,我在这门课上没有效率评分,哈哈。我只是需要完成它,因为周五就要交了,而且我还有一个组装项目要开始。无论如何……
代码操作符类在构造函数中更新了优先级值。
public Operator(char OperatorIn)
{
identity = OperatorIn;
switch (OperatorIn)
{
case '*':
precedence = 2;
break;
case '/':
precedence = 2;
break;
case '=':
precedence = 1;
break;
case '+':
precedence = 1;
break;
case '-':
precedence = 1;
break;
default:
precedence = 0;
break;
}//switch
}//Operator(char)
Structure与Convert方法类似。有很多if(Stack.Count>0)
检查,这可能表明循环和其他if/while内的坏逻辑。但它似乎工作得很好。
public static string Convert(string infix)
{
Stack<Operator> OpStack = new Stack<Operator>();
String Postfix = String.Empty;
Operator Previous = new Operator('x'),
Current = null;
char[] Ops = { '+', '-', '=', '*', '/' };
string term = String.Empty;
foreach (char c in infix) //Iterate through char at a time
{
if (c == '(') //If open paren
OpStack.Push(new Operator(c)); // put on the stack
else if (c == ')') //If close paren
{
Postfix += term + " "; //Output the term
term = ""; // and clear out the term holder
Previous = OpStack.Peek(); //Get a value to know Previous has as real value instead of 'x'
while (Previous.ToChar() != '(') // pop until we reach the open paren
{
if (OpStack.Count > 0)
Current = OpStack.Pop(); //Current becomes what was on top of the stack
if(Current.ToChar() != ')' && Current.ToChar() != '(')
Postfix += Current.ToChar() + " "; // add to output
try //Make sure we have more to pop
{
Previous = OpStack.Pop(); //Previous becomes what was 2nd on the stack
}//try
catch (Exception) //If there's nothing to pop and we're still in this loop
{
return "Error! Mismatched parentheses!"; //Mismatched or missing parenthesis
}//catch
}//while
}//else if
else if (Ops.Contains(c)) //If it's an operator
{
Postfix += term + " "; //output the term
term = ""; // and clear the term holder
Current = new Operator(c); //Assign the current character as Current Op
if (OpStack.Count > 0) //If there are previous ops in stack
{
Previous = OpStack.Peek(); // get top op on stack to compare
if (Previous.GetPrecedence() > Current.GetPrecedence() && OpStack.Count > 0) //Decide between > and =
{
while (Previous.GetPrecedence() > Current.GetPrecedence() && OpStack.Count > 0) //Pop until we find lesser precedence op
{
Previous = OpStack.Pop(); //Remove the compared value from stack
Postfix += Previous.ToChar() + " "; //Add the popped ops to output
if (OpStack.Count > 0) //make sure we aren't looping too far
Previous = OpStack.Peek(); //assign new value before compare occurs
}//while
}//if
else if(Previous.GetPrecedence() == Current.GetPrecedence() && OpStack.Count > 0 && Previous.ToChar() != '=') //Decide between > and =
{
while (Previous.GetPrecedence() == Current.GetPrecedence() && OpStack.Count > 0 && Previous.ToChar() != '=') //Pop until = precedence found
{
Previous = OpStack.Pop(); //Remove the compared value from stack
Postfix += Previous.ToChar() + " "; //Add the popped ops to output
if (OpStack.Count > 0) //make sure we aren't looping too far
Previous = OpStack.Peek(); //assign new value before compare occurs
}//while
}//else if
OpStack.Push(Current); //Once a <= op is found, store the Current op
continue;
}//if
else //If there are no ops on stack
OpStack.Push(Current); // store it immediately
}//else if
else if (c != ' ') //If alphanumeric
term += c; // add into term holder
}//foreach
Postfix += term + " "; //There will be a term left over after the final c, so output it
while(OpStack.Count > 0) //There may also be ops left, so pop them
{
Current = OpStack.Pop();
if (Current.ToChar() == '(' || Current.ToChar() == ')') //If there is a paren remaining
return "Error! Mismatched parentheses!"; // it's because of missing complement or misalignment
Postfix += Current.ToChar() + " "; //output the operator
}//while
return Postfix;
}//Convert v2