首页 > 代码库 > [Stanford] RPN Calculator(model improved version)

[Stanford] RPN Calculator(model improved version)

以前的model是把操作数压入栈里,遇到加减乘除号直接计算结果,改进版的是把操作数和加减乘除号都压入栈里,controller里的接口不变:

CalculatorBrain.h

#import <UIKit/UIKit.h>@interface CalculatorBrain : NSObject-(void)pushOperand:(double)operand;-(double)performOperation:(NSString *)operation;@property(readonly)id program;+(double)runProgram:(id)program;@end

 CalculatorBrain.m

#import "CalculatorBrain.h"@interface CalculatorBrain()@property(nonatomic,strong)NSMutableArray *programStack; //原来的operandStack只能保存运算数,                                                                                         //这个programStack可以同时保存运算数和运算符号。@end@implementation CalculatorBrain@synthesize programStack=_programStack;-(NSMutableArray *)programStack   //需要getter方法做延迟初始化{        if(_programStack==nil)               _programStack=[[NSMutableArray alloc] init];         return _programStack;}-(void)pushOperand:(double)operand  //操作数入栈{       [self.programStack addObject:[NSNumber numberWithDouble:operand]];}-(double)performOperation:(NSString *)operation  //执行运算只需要将运算符入栈再运行计算程序,最后再返回一个值{            [self.programStack addObject:operation]    //添加运算符到栈上,这样栈上就有了操作数和运算符。            return [CalculatorBrain runProgram:self.program]  //这里的返回值是计算结果,所以需要运行计算程序runProgram}-(id)program   //getter方法{          return [self.programStack copy];  //copy做了2件事,一是它生成了一个副本,所以不再是把原本的内部数据交出去,//二是,对可变数组的copy会返回不可变数组吗?不能修改的。现在你调用之后得到program,即使你用了内省,你也没办法对它做什么。}+(double)popOperandOffStack:(NSMutableArray *)stack //递归调用,这里的参数不再是id的,而是NSMutableArray,编译器会把关{         double result=0;          id topOfStack=[stack lastObject];    //如果stack是nil,则会返回nil          if (topOfStack) [stack removeLastObject]; //如果topOfStack是nil,则本句不会被执行      if ([topOfStack isKindOfClass:[NSNumber class]])      {         result=[topOfStack doubleValue];     }          else if([topOfStack isKindOfClass:[NSString class]])        {                   NSString *operation=topOfStack;                   if ([operation isEqualToString:@"+"])                      {             result=[self  popOperandOffStack:stack]+[self popOperandOffStack:stack];         }               else if([@"*" isEqualToString:operation])                       {             result=[self popOperandOffStack:stack]*[self popOperandOffStack:stack];         }                  else if([@"-" isEqualToString:operation])                      {             result=[self popOperandOffStack:stack]-[self popOperandOffStack:stack];         }                else if([@"/" isEqualToString:operation])                      {             result=[self popOperandOffStack:stack]/[self popOperandOffStack:stack];         }         }                         return result;    }+(double)runProgram:(id)program //改,使得不但可以入栈操作符数和运算符,还能入栈变量.比如x、y等{          NSMutableArray *stack;         //建一个本地变量         if ([program isKindOfClass:[NSArray class]])  //用内省判断program是否是数组,然后再赋值给stack            {        stack=[program mutableCopy]; //本地变量stack,用内省对它做了2件事:一是确保了它是数组,二是做了可变的复制,so可吃掉它了      } //因为runProgram实现的方法是用递归把栈上的东西都消化掉,需要它可变才能消化掉。(递归就是循环直到最后的条件成立,最后条件就是一个空数组或者得到一个结果。)stack是静态类型,而mutableCopy返回id。id和静态类型的相互赋值是可以的。编译器不会警告,要自己知道。        return[self popOperandOffStack:stack];  //因为runProgram是类方法,所以popOperandOffStack也是一个类方法,self是class。   //主要就是对计算的结果进行出栈。如果栈顶是数字就返回数字,如果是个运算符,就对其求值。} //如果传进来的不是数字和字符串“+”“-”“*”“/”,那么也不会崩溃。因为popOperandOffStack中的if和else if都不满足,就执行return result,也就是0.所以我们不怕传进来垃圾数组,这很重要。

 

[Stanford] RPN Calculator(model improved version)