先来个运行截图吧:
老师要求用c#写个计算器,虽然写了无数遍了(用c写,c++写,java写...),于是这次决定用中缀撸个新鲜的计算器,和原先我那个java用递归方法写的相比,这里实在是让代码简洁了许多许多,而且浮点运算,正负号都可以支持,果然还是体现了数据结构的美丽和强大
先写两个栈:
namespace Utils_Calculate
{
public class Static_Double {
private double[] opnd = new double[500];
private int cur = -1;
public void Push(double p){
if (cur < 500) opnd[++cur] = p;
}
public bool IsEmpty(){
return cur < 0 ? true : false;
}
public double Pop() {
if (cur >= 0) return opnd[cur--];
else return 0;
}
public void clear(){
cur = -1;
}
}
public class Static_Char {
private char[] optr = new char[500];
private int cur = -1;
public void Push(char c){
if (cur < 500) optr[++cur] = c;
}
public bool IsEmpty(){
return cur < 0 ? true : false;
}
public char Pop(){
if (cur >= 0) return optr[cur--];
else return '\n';
}
public void clear(){
cur = -1;
}
}
}
具体代码如下:
namespace Utils_Calculate
{
class CharUtil {
public static bool IsDigit(char c){
return (c >= 48 && c <= 57 || c == '.') ? true : false;
}
}
public class Rpn_Calculate: IRpn_Calculate
{
//定义优先级,即当前所指运算符优先级为0,栈顶元素优先级为-1
private int cur_pri = 0, top_pri = -1;
//数据栈
Static_Double opnd = new Static_Double();
//符号栈
Static_Char optr = new Static_Char();
//优先级定义
private int GetPRI(char c){
if (c == '+' || c == '-') return 1;
if (c == '*' || c == '/') return 2;
if (c == '(' || c == ')') return 0;
return -1;
}
//计算函数
private double Cal(double before,char mark,double after){
if (mark == '+') return before + after;
if (mark == '-') return before - after;
if (mark == '*') return before * after;
if (mark == '/') return before / after;
throw new System.Exception();
}
//计算
public double Rnp(char[] str,int len){
try
{
for (int i = 0; i < len; i++){
string x = "";double read_x = 0;char c = ' ';
//如果c是数字或小数点
if (CharUtil.IsDigit(c=str[i])){
x += c;
//循环读数包括小数点(比如8.88+7.777,这里会分三次读,第一次循环读入8.88,第二次读入+,第三次循环读入7.777)
while (i < len-1&& CharUtil.IsDigit(c = str[++i]))
x += c;
read_x = double.Parse(x);
//读出的数据入数据栈
opnd.Push(read_x);
}
//如果c是运算符,并且c的优先级高于栈顶符号的优先级,则c入栈
if ((cur_pri = GetPRI(c)) >= 0) {
if (c=='('|| cur_pri > top_pri){
top_pri = cur_pri;
optr.Push(c);
//如果c是')',则符号栈的元素不断出桟、运算,直到遇到左括号
}else if (c == ')'){
char _c =' '; double result = 0;
while ((_c=optr.Pop())!='('){
double after = opnd.Pop();
result = opnd.Pop();
result = Cal(result, _c,after);
opnd.Push(result);
}
//栈顶优先级更新
if (optr.IsEmpty())top_pri = -1;
else{
char char_top = optr.Pop();
top_pri = GetPRI(char_top);
optr.Push(char_top);
}
}else{
//当前运算符优先级低于栈顶,先出栈计算(运算符出桟一个,数据栈出桟两个),再将当前运算符入栈
opnd.Push(Stack_Cal(optr.Pop()));
optr.Push(c);
top_pri = GetPRI(c);
}
}
}
double final_result = 0;
//最后结束的时候两个栈里面的优先级是有序的,需要出桟计算一波
while (!optr.IsEmpty()){
char _c = optr.Pop();
double after = opnd.Pop();
final_result = opnd.Pop();
final_result = Cal(final_result, _c, after);
opnd.Push(final_result);
}
//返回结果
double _result=opnd.Pop();
Reset();
return _result;
}
catch (System.Exception){
throw new System.Exception("请不要乱输谢谢..");
}
}
//还原配置
private void Reset() { cur_pri = 0; top_pri = -1; opnd.clear();optr.clear(); }
//出栈计算(运算符出桟一个,数据栈出桟两个)
private double Stack_Cal(char mark){
double after = opnd.Pop();
double before = opnd.Pop();
return Cal(before, mark, after);
}
}
}
class Program
{
static void Main(string[] args)
{
//测试代码:
Rpn_Calculate calculator = new Rpn_Calculate();
const string test = "1+2*(3-4)/5.5";
double result = calculator.Rnp(test.ToCharArray(), test.Length);
Console.WriteLine(result);
Console.ReadKey();
}
}
做个UI界面也是个不错的想法: