陆陆续续更新这个计算器用了一个礼拜了,今天无论如何也要把它更完。笔者有点追求完美,再者每天都有课,晚上还有作业,还有每晚都会写一些其他的博文。
上一次漏了写如何实现计算的。思路如下:
之前得到一个栈2stack2,里面存的是逆波兰式。但是注意了,式子是反过来的。因为栈只能从栈顶写入,从栈顶拿出。所以,必须把栈2的数反过来。
下面是转换的代码:
// //将栈2数值倒过来 // private void UpSideDown() { string[] strTemp = stack2.ToArray(); //将栈stack2数值临时存储在数组里 stack2.Clear(); //将栈stack2清空 for(int i=strTemp.Length-1;i>=0;i--) { stack2.Push(strTemp[i]); } }
将栈的数值倒过来之后,我们就可以进行计算了,计算的思路如下:按下图步骤
1:从栈顶取元素,如果是数字直接存入新栈 2:如果是操作符,则不存入,将新栈的前两个元素依次取出,先取出的数字放在运算符右边,后取出的放在左边 3:计算的结果放回新栈。重复以上步骤,知道计算完。
注意!新栈保存的数字,所以要注意栈的类型。
// //计算四则运算 // public double DoMath() { var stackTemp = new Stack<double>(); try { while (myStack2.Count != 0) { if (!IfNumber(myStack2.Peek())) { double d1 = stackTemp.Pop(); double d2 = stackTemp.Pop(); switch (myStack2.Pop()) { case "+": stackTemp.Push(d2 + d1); break; case "-": stackTemp.Push(d2 - d1); break; case "*": stackTemp.Push(d2 * d1); break; case "/": stackTemp.Push(d2 / d1); break; }//end switch }//end if else { stackTemp.Push(Convert.ToDouble(myStack2.Pop())); } }//end while return stackTemp.Pop(); } catch { return 0; } }
四则混合运算的大体步骤和解决思路就这么多,现在开始解决如何确保用户在乱输入公式以及得到的公式该怎么解析(前面提到的问题:就是当接受了加括号的一元运算符比如:1+(-2)。转换得到的式子是不能正确计算的。)
思路一:怎么解决用户乱输入数字
用栈保存用户每次按的按键内容,除了第一次输入外,在每次输入的时候与栈顶元素进行比较。如果连续两次输入操作符,则视第二次有效:
private string str = ""; //声明切定义一个空字符串,用于在label显示用户输入 Stack<string> tempStack = new Stack<string>(); //声明一个数组,,用去存储用户输入 //判断用户点击是否有效 public void IfValid(string s) { if (tempStack != null) { if (Calculate.IfNumber(s)) //如果用户按得是数字,则输入有效 { tempStack.Push(s); } else { if (!Calculate.IfNumber(tempStack.Peek())) //如果用户连续两次按的是操作符,则视第二次有效 { tempStack.Pop(); tempStack.Push(s); } else tempStack.Push(s); } }//end if else { tempStack.Push(s); } str = ""; string[] tempStr = tempStack.ToArray(); //将得到的数组反转 for (int i = 0; i < tempStr.Length / 2; i++) { string temp = tempStr[i]; tempStr[i] = tempStr[tempStr.Length - i - 1]; tempStr[tempStr.Length - i - 1] = temp; } foreach (var item in tempStr) str += item; label1.Text = str; } private void button1_Click(object sender, EventArgs e) { IfValid(button1.Text); } private void button2_Click(object sender, EventArgs e) { IfValid(button2.Text); }
笔者有很多地方都用到将数组元素前后倒过来的代码,但却没有将其写成独立函数,造成代码的冗余。