实验题目
设计一个支持连续计算的简单计算器,其过程包括项目分析,界面设计,代码编写和运行调试。通过该项目的开发,使读者进一步了解基于图形用户界面的Windows应用程序的开发过程,并通过项目实训的扩展练习加深印象,为开发较为复杂的应用程序打下基础。
实验方案
设计思路: 有两个栈 一个存放数字 一个存放运算符
1、将表达式字符串转换成字符数组 遍历字符数组
2、判断表达式是否合法,合法的话再进行计算
3、如果是数字 直接存放到数字栈
4、如果是符号:分为两种情况
(1) 如果符号栈为空 直接将符号入栈
(2)如果符号栈不为空
a、当运算符和栈内的运算符进行比较 如果当前的运算符的优先级低于或者等于栈中的运算符,就需要从数栈中pop出两个数,再从符号栈中pop出一个符号,进行运算, 将得到的结果push进数栈,然后将当前的符号push符号栈;
b、如果当前的操作符的优先级大于栈中的运算符 就直接入符号栈
4、当表达式扫描完毕 就顺序从数栈和符号栈pop出相应的数和符号 并运行
5、最后数栈中只有一个数字 即为表达式的结果
设计界面
功能展示
实验总结
本次实验代码体量较小,所用到的也是原来在数据结构课程中学过的栈,理解起来相对容易。基础部分主要参考书上代码以及网上的内容。拓展部分主要参考网上的内容自行理解加以修正。整体碰见以下问题,现加以分析:
1、第一次设计时并没有参考书上代码,自己写的比较简单,没有使用栈。但发现在扩展功能需要完成优先级时很困难,故又利用栈重新设计。
2、在拓展部分出现sin,cos的计算功能,刚开始只是在原来基础上简单添加,后来发现没有考虑优先级的问题,加到栈里后又发现这两个是单目运算符,还要再考虑单目运算符和双目运算符的判断。
3、拓展功能还提到了专用领域的计算器,但没有做出来,希望以后有机会可以接触一下。
4、第一次实现窗体桌面程序,虽然内容比较简单,但是在设计过程中不仅仅需要思考怎样可以得到正确的运算结果,还需要考量用户怎么使用会更加舒适,这是自己从来没有接触过的。
源码展示
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace myCalculator
{
public partial class Form_Main : Form
{
string ptr = ""; //算数表达式
Stack<int> lastlen = new Stack<int>();//添加操作数之前的算术表达式的长度
Stack<int> lastlenT = new Stack<int>();//添加操作数之前的文本框的长度
bool start = true;
string lastAns = "0";//标志初始化
Stack<double> nums = new Stack<double>();//操作数
Stack<char> ops = new Stack<char>();//运算符
public Form_Main()
{
InitializeComponent();
textDisplay.Text = "0";
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void TextDisplay_TextChanged(object sender, EventArgs e)
{
}
private void Btn_2_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += "2";
ptr += "2";
}
private void Btn_3_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += "3";
ptr += "3";
}
private void Btn_4_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += "4";
ptr += "4";
}
private void Button6_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += "5";
ptr += "5";
}
private void Btn_6_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += "6";
ptr += "6";
}
private void Btn_7_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += "7";
ptr += "7";
}
private void Btn_8_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += "8";
ptr += "8";
}
private void Btn_9_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += "9";
ptr += "9";
}
private void Btn_equal_Click(object sender, EventArgs e)
{
textDisplay.Clear();
string ans = Cal(ptr); //调用求值算法
lastlen.Clear();
lastlenT.Clear();
lastlen.Push(0);
lastlenT.Push(0);
textDisplay.Text += ans;
ptr = ans;
double result;
bool flag = double.TryParse(ans, out result);
if (!flag || ans == "0") start = true;
}
private void Button11_Click(object sender, EventArgs e)//点
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
int len = textDisplay.Text.Length;
if (len == 0 || (textDisplay.Text[len - 1] < '0' || textDisplay.Text[len - 1] > '9') && textDisplay.Text[len - 1] != '.')
{
textDisplay.Text += "0.";
ptr += "0.";
}
else
{
textDisplay.Text += ".";
ptr += ".";
}
}
private void Btn_1_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += "1";
ptr += "1";
}
private void Btn_0_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += "0";
ptr += "0";
}
private void Btn_add_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length); //没有添加前的算术表达式的长度
lastlenT.Push(textDisplay.Text.Length);
if (ptr == "")
{
textDisplay.Text += "+";
ptr += "0+"; //把单目运算符“+”改成双目运算符
}
else
{
textDisplay.Text += "+";
ptr += "+";
}
}
private void Btn_clear_Click(object sender, EventArgs e)
{
textDisplay.Text = "0";
ptr = "";
lastlenT.Clear();
lastlen.Clear();
start = true;
}
private void Btn_sub_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += "-";
int len = ptr.Length;
if (len != 0 && (ptr[len - 1] == ')' || (ptr[len - 1] >= '0' && ptr[len - 1] <= '9')))
ptr += "+-"; //把“-”改成单目运算符
else ptr += "-";
}
private void Btn_multi_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += "*";
ptr += "*";
}
private void Btn_div_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += "/";
ptr += "/";
}
private void Button1_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += "(";
ptr += "(";
}
private void Btn_right_bracket_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
textDisplay.Text += ")";
ptr += ")";
}
private bool check(string str) //检查算术表达式是否匹配
{
int jd = 0, num = 0;
int len = str.Length;
int st = 0, ed = len - 1;
while (str[st] == '(' && st < ed) st++;
while (str[ed] == ')' && ed > 0) ed--;
if ((str[st] < '0' || str[st] > '9') && str[st] != '-' && str[st] != 'S' && str[st] != 's' && str[st] != 'c') return false;
if ((str[ed] < '0' || str[ed] > '9') && str[ed] != '!' && str[ed] != '^') return false;
for (int i = 0; i < len; i++)
{
if (str[i] == '+' || str[i] == '*' || str[i] == '/' || str[i] == '%') jd++;
if ((str[i] >= '0' && str[i] <= '9') || str[i] == '.') jd = 0;
if (jd >= 2) return false;
}
jd = 0;
for (int i = 0; i < len; i++)
{
if (str[i] == '(') jd++;
else if (str[i] >= '0' && str[i] <= '9' && jd > 0) num++;
else if (str[i] == ')')
{
if (jd == 0 || num == 0) return false;
jd--;
}
}
if (jd > 0) return false;
return true;
}
private int isp(char op)
{
// s 表示sin, c 表示cos
if (op == '#') return 0;
if (op == '(') return 1;
if (op == '*' || op == '/' || op == 'c' || op == 's') return 5;
if (op == '+' || op == '-') return 3;
if (op == ')') return 7;
return -1;
} //返回栈中算符优先级
private int icp(char op)
{
if (op == '#') return 0;
if (op == '(') return 7;
if (op == '*' || op == '/') return 4;
if (op == 'c' || op == 's') return 6;
if (op == '+' || op == '-') return 2;
if (op == ')') return 1;
return -1;
}//返回栈外算符优先级
private double compute(double l, char op, double r)
{
if (op == '+') return l + r;
if (op == '-') return l - r;
if (op == '*') return l * r;
if (op == '/') return l / r;
return 0;
} //计算运算符
private bool trans(ref string str)//检测第一位是不是负号 ref关键字--让参数按照引用传递
{
int num = 0;
for (int i = 0; i < str.Length; i++)
{
if (str[i] == '-') num++;
else break;
}
str = str.Substring(num);
if (num % 2 == 0) return false;
return true;
}
private string Cal(string str) //用堆栈实现中缀表达式求值
{
if (str == "") str = "0";
if (str == "∞") return str;
if (!check(str)) return "Syntax Error";
str += '#';
nums.Clear();
ops.Clear();
ops.Push('#');
for (int i = 0; i < str.Length; i++)
{
bool number = false;
string tmp = "";
while ((str[i] >= '0' && str[i] <= '9') || str[i] == '.' || str[i] == '-' )
{
number = true;
tmp += str[i];
i++;
}
bool flag;
if (number)
{
flag = trans(ref tmp);
double res;
bool success = double.TryParse(tmp, out res);
if (flag) res = -res; //把减号转成负号
if (success) nums.Push(res);
else return "Syntax Error";
}
flag = true;
while (flag)
{
if (icp(str[i]) > isp((char)ops.Peek()))
{
ops.Push(str[i]);
break;
}
else if (icp(str[i]) < isp((char)ops.Peek()))
{
double r = nums.Pop();
char op = ops.Pop();
if (op == 's' || op == 'c')
{
if (op == 's') nums.Push(Math.Sin(r * Math.PI / 180));//弧度角度转换
else nums.Push(Math.Cos(r * Math.PI / 180));//弧度角度转换
}
else
{
double l = nums.Pop();
if (op == '/' && r == 0) return "∞";
nums.Push(compute(l, op, r));
}
}
else
{
ops.Pop();
break;
}
}
}
if (nums.Count > 1) return "Syntax Error";
lastAns = nums.Pop().ToString();
return lastAns;
}
private void Btn_sin_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
int len = textDisplay.Text.Length;
if (len > 0 && ((textDisplay.Text[len - 1] >= '0' && textDisplay.Text[len - 1] <= '9') || textDisplay.Text[len - 1] == ')'))
{
textDisplay.Text += "*";
ptr += "*";
}
textDisplay.Text += "sin(";
ptr += "s(";
}
private void Btn_cos_Click(object sender, EventArgs e)
{
if (start)
{
ptr = "";
textDisplay.Clear();
start = false;
}
lastlen.Push(ptr.Length);
lastlenT.Push(textDisplay.Text.Length);
int len = textDisplay.Text.Length;
if (len > 0 && ((textDisplay.Text[len - 1] >= '0' && textDisplay.Text[len - 1] <= '9') || textDisplay.Text[len - 1] == ')'))
{
textDisplay.Text += "*";
ptr += "*";
}
textDisplay.Text += "cos(";
ptr += "c(";
}
private void Btn_backspace_Click(object sender, EventArgs e)
{
string str = textDisplay.Text;
if (str == "Syntax Error" || str == "∞" || str == "Math Error" || str == "Too big")
{
textDisplay.Text = "0";
start = true;
return;
}
textDisplay.Text = textDisplay.Text.Substring(0, lastlenT.Pop());
if (ptr.Length != 0)
{
ptr = ptr.Substring(0, lastlen.Pop());
}
if (textDisplay.Text.Length == 0)
{
textDisplay.Text = "0";
lastlenT.Push(0);
start = true;
}
}
}
}