【栈】控制台计算器实现四则运算

这篇文章主要介绍实现一个控制台界面的计算器,计算用户输入一个完整的、有效的、四则运算式。

一下是具体步骤:

1. 定义一个操作的基类,用来实现类似于 "A+B“ 的运算

View Code
    public class Operation
{
public Operation()
{ }

public Operation(int a, int b)
{
_numA = a;
_numB = b;
}

protected int _numA, _numB;

public int NumA {
get { return _numA; }
set { _numA = value; }
}
public int NumB {
get { return this._numB; }
set { this._numB = value; }
}

public virtual int Calculate()
{
return _numA + _numB;
}
}

2. 定义对应的四则运算类

加法运算,直接使用父类默认的方法
    class AddOperation:Operation
{
public AddOperation():base()
{ }

public AddOperation(int a, int b):base(a, b)
{

}
}
减法运算
    public class MinusOperation:Operation
{
public MinusOperation()
: base()
{ }

public MinusOperation(int a, int b)
: base(a, b)
{ }

public override int Calculate()
{
return _numA - _numB;
}
}
乘法运算
    public class MultipleOperation:Operation
{
public MultipleOperation()
{ }

public MultipleOperation(int a, int b)
: base(a, b)
{ }

public override int Calculate()
{
return _numA * _numB;
}
}
除法运算
    public class DivideOperation:Operation
{
public DivideOperation()
{ }

public DivideOperation(int a, int b)
: base(a, b)
{ }

public override int Calculate()
{
int result = 0;
int.TryParse(( _numA / _numB).ToString(),out result);
return result;
}
}

3. 定义辅助方法

将栈里面的元素反转,同时将反转后的栈作为结果返回
        static Stack ReverseStack(Stack stack)
{
Stack temp = new Stack();
while (stack.Count > 0)
{
temp.Push(stack.Pop());
}
return temp;
}
从栈里面按栈的顺序获取表达式
        static string GetEquationFromStack(Stack stack)
{
StringBuilder equationBuilder = new StringBuilder();
while (stack.Count > 0)
{
equationBuilder.Append(stack.Pop().ToString());
}
return equationBuilder.ToString();
}
计算表达式并重置参与运算的符号和式子中的两个数值
        private static void BeginCalculate(StringBuilder builderA, StringBuilder builderB, ref string sign)
{
//使用反射获取对应的四则运算类
Operation operation = (Operation)Assembly.Load("Calculator").CreateInstance(string.Format("Calculator.{0}", GetMappedString(sign)));
operation.NumA = int.Parse(builderA.ToString());
operation.NumB = int.Parse(builderB.ToString());
string result = operation.Calculate().ToString();

//计算完成后需要进行如下操作
// 1.用计算的结果替换第一个数字,用来参加下一次的运算
// 2.将符号重置为空
// 3.将第二个数字重置
builderA.Clear();
builderA.Append(result);
sign = string.Empty;
builderB.Clear();
}
通过传入的符号返回对应的操作类的名称,返回值会用于反射得到对应的类。返回值和类的名称一致,便于操作
        static string GetMappedString(string c)
{
switch (c)
{
case "+":
return "AddOperation";
case "-":
return "MinusOperation";
case "*":
return "MultipleOperation";
case "/":
return "DivideOperation";
default:
return string.Empty;
}
}

4. 定义对于简单算式(不包含括号的算式)的运算

View Code
        private static string StackCalculate(string equation)
{
string sign = string.Empty; //操作符,“+”、“-”、“*”、“/”
string result = string.Empty;
StringBuilder builderA = new StringBuilder(); //参与运算的第一个数字
StringBuilder builderB = new StringBuilder(); //参与运算的第二个数字
Stack stack = new Stack(); //这里的栈用来存放低优先级(+、-)的运算

char[] chars = equation.ToCharArray();

//不论算式的第一个字符是什么都传给第一个数字,这样可以避免第一个字符是“-”对操作的影响
builderA.Append(chars[0]);

//遍历剩下的字符串,把所有乘除法用其对应的结果代替,并把结果压到栈里
for (int i = 1; i < chars.Length; i++)
{
switch (chars[i])
{
case '+':
case '-':
if (sign == string.Empty)
{
//如果是加减号,运算符值为空,则给运算符赋值为加号或者减号
sign = chars[i].ToString();
}
else
{
//如果运算符不为空,则表示builderA,sign 和 builderB可以组成一个完成的算式
//开始计算
BeginCalculate(builderA, builderB, ref sign);

//给运算符赋值为加号或者减号
sign = chars[i].ToString();
}
break;
case '*':
case '/':
if (sign == string.Empty)
{
//运算符值为空,则给运算符赋值为乘号或者除号
sign = chars[i].ToString();
}
else if (sign == "+" || sign == "-")
{
//如果之前的运算符是加减号,则重置存储在builderA, sign 和builderB组成的式子
//并把之前的builderA 和运算符压到栈里
stack.Push(builderA.ToString());
stack.Push(sign);
builderA.Clear();
builderA.Append(builderB.ToString());
builderB.Clear();
sign = chars[i].ToString();
}
else
{
//如果运算符不为空,且是乘除号,则进行计算
BeginCalculate(builderA, builderB, ref sign);

//给运算符赋值
sign = chars[i].ToString();
}
break;
default:
//当前字符不是运算符
if (sign == string.Empty)
{
//如果操作符为空,则表示现在需要给参与运算的第一个数字赋值
builderA.Append(chars[i]);
}
else
{
//如果操作符不为空,则表示现在需要给参与运算的第二个数字赋值
builderB.Append(chars[i]);
}
break;
}
}

//处理第一次循环剩余的算式,并把结果压入栈里
if (sign != string.Empty)
{
BeginCalculate(builderA, builderB, ref sign);
stack.Push(builderA.ToString());
}

//对栈里存放的低优先级表达式进行处理
if (stack.Count < 1)
{
return "Error";
}
else if (stack.Count == 1)
{
return stack.Pop().ToString();
}
else
{
//从栈里获取低优先级表达式
string finalEquation = GetEquationFromStack(ReverseStack(stack));
//对表达式进行计算,并将结果返回
return StackCalculate(finalEquation);
}
}

5. 定义复杂算式(有括号)的运算,会调用4里面创建的方法

View Code
        public static string Run(string equation)
{
Stack stack = new Stack(); // 1.新建一个栈,用来存放部分表达式

string result = string.Empty;

// 2.遍历所有字符,把所有括号里面的算式转换成对应的结果
// 比如 “1+2+3(9-7/1)+5*4”就会转换成“1+2+3*2+5*4”
foreach (char c in equation.ToCharArray())
{
// 2.1只要遇到的字符不是“)”就压到栈里面
if (c != ')')
{
stack.Push(c);
}
else
{
// 2.2如果遇到“)”,就把栈顶的值取出来,直到遇到“(”
// 此时就会得到这个括号里完整的算式
Stack tempStack = new Stack();
while (stack.Peek().ToString() != "(")
{
tempStack.Push(stack.Pop());
}
stack.Pop(); //弹出栈顶元素

int temp = 0; // 临时变量,用来支持下面判断语句的正常运行

// 2.3判断栈顶的元素是不是数字,如果是数字,则表示该数字和括号里面的式子是乘法关系
//这时需要人为的往栈里面压入一个"*"
if (int.TryParse(stack.Peek().ToString(), out temp))
{
stack.Push('*');
}

// 2.4把括号里面式子的结果压到栈里
stack.Push(StackCalculate(GetEquationFromStack(tempStack)));
}
}

//3. 计算栈里面存放的最终表达式,并返回最终结果
result = StackCalculate(GetEquationFromStack(ReverseStack(stack)));
return result;
}

6. 测试

View Code
        static void Main(string[] args)
{
Console.WriteLine("Please input the equation you want to calculate:");
string equation = Console.ReadLine();

Console.WriteLine("The result is {0}", Run(equation));

Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}


运行结果如下图:












posted @ 2012-02-28 21:29  silverbullet11  阅读(585)  评论(2编辑  收藏  举报