用Objective-C的foundation框架解决表达式求值问题
主要思想:
本程序分2个类
一个是ExpressionString类,主要用于存储表达式以及对它进行求值。以下是该类中的内容:
(NSString *)expString//用于存储要计算的表达式;
-(NSString*)caculateExpression//就用于计算该表达式的值。
另外一个类是ExpressionEvaluation,此类用于辅助ExpressionString类来对表达式进行求值。以下是该类中的内容:
-(id) init; //初始化函数
-(BOOL) isDigital; //判断是否是数字
-(NSString*) precede:(NSString*) a; //判断当前操作符和栈顶操作符的优先级
-(double) compute: (NSString*) opnt anOtherStr: (NSString*) a; //出栈计算
在main函数中,只需要3步就行了。定义、发送赋值消息、输出结果。3个步骤如下:
ExpressionString *es = [ExpressionString alloc];
[es setExpString:@"10÷6×7+15-8"];
//[es setExpString:@"10÷÷6×7+15-8"]; 此步骤是用于检查错误的测试用例,当使用这步时,系统会输出错误提示信息。
//[es setExpString:@"1000÷2"]; 此步骤用于检测整除之后输出整型,而不是浮点型的值。
NSLog(@"%@",[es caculateExpression]);
具体代码如下:共5个文件。
//
// ExpressionString.h
// exp1_2
//
// Created by junz on 12/27/14.
// Copyright (c) 2014 Caspar. All rights reserved.
// #import <Foundation/Foundation.h> @interface ExpressionString : NSObject
@property NSString *expString;
- (NSString*)caculateExpression;
@end
//
// ExpressionString.m
// exp1_2
//
// Created by junz on 12/27/14.
// Copyright (c) 2014 Caspar. All rights reserved.
// #import "ExpressionString.h"
#import "ExpressionEvaluation.h"
@implementation ExpressionString
@synthesize expString;
- (NSString*)caculateExpression
{
NSMutableArray *array = [[NSMutableArray alloc] init];
for (int i = ; i < [self.expString length]; i++)//初始化构造数组array存放所有字符
{
NSMutableString *s = [[NSMutableString alloc] init];
s = [NSMutableString stringWithString: [self.expString substringWithRange:NSMakeRange(i, )]];
if ([s isEqualToString:@"÷"]) s = [NSMutableString stringWithString: @"/"];
else if ([s isEqualToString:@"×"]) s = [NSMutableString stringWithString: @"*"];
else ;
array[i] = s;
}
array[[array count]] = @"#";//在array数组的末尾加上#作判断符用
//初始化2个栈,OPTR存放操作符,OPND存放操作数
NSMutableArray *OPTR = [[NSMutableArray alloc] init];
NSMutableArray *OPND = [[NSMutableArray alloc] init];
ExpressionEvaluation *current = [ExpressionEvaluation alloc]; //设置一个遍历指针current,从0开始对表达式进行遍历
ExpressionEvaluation *next = [ExpressionEvaluation alloc];
double sum = ; //表达式中操作数的值
int i = , k = -, j = -;//i用来遍历表达式,k用来记录OPND的大小,j用来记录OPTR的大小
int breakflag = ;
current.str = array[i];
while (![current.str isEqualToString: @"#"])//表达式未遍历完,则不断循环遍历
{
while ([current isDigital]) //判断当前指针所指的字符是不是数字,如果是,则将数字存入OPND
{
sum = * sum + ([[current str] intValue]);
if (i >= ([array count] - ))
{
break;
}
[current setStr: array[++i]];
if (![current isDigital]) {
OPND[++k] = [NSString stringWithFormat:@"%f", sum];
sum = ;
}
}
NSInteger flag = ; //当current指针指向操作符时,则需要与OPTR栈顶元素进行比较
double temp = ;
if (i < ([array count] - )) {//判断表达式的正确性
[next setStr: array[i+]];
if (![next isDigital] && ((![current.str isEqualToString:@")"] && ![next.str isEqualToString:@"("]) || [current.str isEqualToString:@")"] && [next.str isEqualToString:@"("]) { //情况1:")(";情况2:"**"或者"//"等等 breakflag = ;
break;
}
}
//如果OPTR栈为空,则将当前current所指的操作符进栈
if ((j == -) && ![current.str isEqualToString:@"#"])
{
OPTR[++j] = [current str];
[current setStr: array[++i]];
flag = ;
}
//如果当前OPTR不为空,则将current所指的操作符与OPTR栈顶元素进行比较
while (flag && (j >= )) {
ExpressionEvaluation *aa = [ExpressionEvaluation alloc];
ExpressionEvaluation *bb = [ExpressionEvaluation alloc];
if ([current.str isEqualToString:@"#"] && (j == -)) {
break;
}
switch ([[current precede:OPTR[j]] isEqualToString:@"<"])
{
case true: //如果OPTR栈顶元素小于current所指的操作符,则current所指的操作符进栈
OPTR[++j] = [current str];
[current setStr: array[++i]];
flag = ;
break;
case false:
switch ([[current precede:OPTR[j]] isEqualToString:@"="])
{
case true: //如果OPTR栈顶元素等于current所指的操作符,则消去括号,并使current指向下一个字符
j = j - ;
[current setStr: array[++i]];
break;
case false:
switch ([[current precede:OPTR[j]] isEqualToString:@">"])
{ case true://如果OPTR栈顶元素大于current所指的操作符,出栈计算,将结果入OPND栈
aa.str = OPND[k--];
bb.str = OPND[k--];
temp = [bb compute: OPTR[j--] anOtherStr:aa.str];
OPND[++k] = [NSString stringWithFormat:@"%f", temp];
break;
case false: breakflag = ;break; //判断优先权为0时候的情况
}
}
default: break;
}
if ((j == -) && ![current.str isEqualTo:@"#"])//判断OPTR栈是否为空,为空则将current所指的操作符入栈
{
OPTR[++j] = [current str];
[current setStr: array[++i]];
flag = ;
}
}
}
if (breakflag) {
//以下代码主要是为了防止类似10/2=5.000000的问题,程序从后往前逐个删除0,使最终得到10/2=5。
NSMutableString *ss = [NSMutableString stringWithString:OPND[]];
while ([[ss substringWithRange:NSMakeRange(ss.length-, )] isEqualToString:@""]) {
[ss deleteCharactersInRange:NSMakeRange(ss.length-, )];
}
if ([[ss substringWithRange:NSMakeRange(ss.length-, )] isEqualToString:@"."]) [ss deleteCharactersInRange:NSMakeRange(ss.length-, )];
return ss;
}
else return @"This is not a correct expression, can not evaluate";
}
@end
//
// ExpressionEvaluation.h
// exp1_2
//
// Created by junz on 12/27/14.
// Copyright (c) 2014 Caspar. All rights reserved.
// #import <Foundation/Foundation.h> @interface ExpressionEvaluation : NSObject
@property NSMutableString* str; -(id) init;
-(BOOL) isDigital; //判断是否是数字
-(NSString*) precede:(NSString*) a; //判断当前操作符和栈顶操作符的优先级
-(double) compute: (NSString*) opnt anOtherStr: (NSString*) a; //出栈计算
@end
//
// ExpressionEvaluation.m
// exp1_2
//
// Created by junz on 12/27/14.
// Copyright (c) 2014 Caspar. All rights reserved.
// #import "ExpressionEvaluation.h" @implementation ExpressionEvaluation
@synthesize str; -(id) init
{
self.str = [[NSMutableString alloc] init];
return self;
}
-(BOOL) isDigital
{
if (([self.str isGreaterThanOrEqualTo:@""]) && ([self.str isLessThanOrEqualTo:@""])) {
return YES;
}
else return NO;
}
-(NSString*) precede:(NSString*) a
{
NSInteger i = , j = ;
NSArray *priori = [[NSArray alloc] initWithObjects:
[NSArray arrayWithObjects:@">",@">",@"<",@"<",@"<",@">",@">", nil],
[NSArray arrayWithObjects:@">",@">",@"<",@"<",@"<",@">",@">", nil],
[NSArray arrayWithObjects:@">",@">",@">",@">",@"<",@">",@">", nil],
[NSArray arrayWithObjects:@">",@">",@">",@">",@"<",@">",@">", nil],
[NSArray arrayWithObjects:@"<",@"<",@"<",@"<",@"<",@"=",@"", nil],
[NSArray arrayWithObjects:@">",@">",@">",@">",@"=",@"",@">", nil],
[NSArray arrayWithObjects:@"<",@"<",@"<",@"<",@"<",@"",@"=", nil],
nil];
if ([a isEqualToString:@"+"]) i = ;
else if ([a isEqualToString:@"-"]) i = ;
else if ([a isEqualToString:@"*"]) i = ;
else if ([a isEqualToString:@"/"]) i = ;
else if ([a isEqualToString:@"("]) i = ;
else if ([a isEqualToString:@")"]) i = ;
else if ([a isEqualToString:@"#"]) i = ;
else ; if ([self.str isEqualToString:@"+"]) j = ;
else if ([self.str isEqualToString:@"-"]) j = ;
else if ([self.str isEqualToString:@"*"]) j = ;
else if ([self.str isEqualToString:@"/"]) j = ;
else if ([self.str isEqualToString:@"("]) j = ;
else if ([self.str isEqualToString:@")"]) j = ;
else if ([self.str isEqualToString:@"#"]) j = ;
else ; return priori[i][j];
}
-(double) compute: (NSString*)opnt anOtherStr: (NSString*)a
{
double sum = ;
if ([opnt isEqualToString:@"+"]) sum = [self.str doubleValue] + [a doubleValue];
else if ([opnt isEqualToString:@"-"]) sum = [self.str doubleValue] - [a doubleValue];
else if ([opnt isEqualToString:@"*"]) sum = [self.str doubleValue] * [a doubleValue];
else if ([opnt isEqualToString:@"/"]) sum = [self.str doubleValue] / [a doubleValue];
else ;
return sum;
}
@end
//
// main.m
// exp1_2
//
// Created by junz on 12/27/14.
// Copyright (c) 2014 Caspar. All rights reserved.
// #import "ExpressionString.h"
#import "ExpressionEvaluation.h" int main(int argc, const char * argv[]) {
@autoreleasepool {
ExpressionString *es = [ExpressionString alloc];
// [es setExpString:@"1000÷2"];
// [es setExpString:@"10÷6×7+15-8"];
// [es setExpString:@"10÷÷6×7+15-8"]; //属于错误情况2
[es setExpString:@"10÷(6+2)(7)+15-8"]; //属于错误情况1
NSLog(@"%@",[es caculateExpression]);
}
return ;
}
总结:此程序能求解正确表达式的值,但是容错性稍微差了些,比如在main函数中,发这样一条消息:[es setExpString:@"10÷(6+2)(+15-8"];程序直接奔溃,没有实现很好的容错。
解决方法:
需要针对ExpressionString类中的compute方法进行改进。
1、对OPND和OPTR数组取数据时,把取出来的数据在OPND和OPTR中删除;
2、在返回值时,通过判断OPND和OPTR的大小来进行,而不是直接返回OPND[0]。
由于时间问题,此改进的操作等有时间的时候再搞。现在先暂且放一放。
用Objective-C的foundation框架解决表达式求值问题的更多相关文章
- java实现算术表达式求值
需要根据配置的表达式(例如:5+12*(3+5)/7.0)计算出相应的结果,因此使用java中的栈利用后缀表达式的方式实现该工具类. 后缀表达式就是将操作符放在操作数的后面展示的方式,例如:3+2 后 ...
- 刁肥宅详解中缀表达式求值问题:C++实现顺序/链栈解决
1. 表达式的种类 如何将表达式翻译成能够正确求值的指令序列,是语言处理程序要解决的基本问题,作为栈的应用事例,下面介绍表达式的求值过程. 任何一个表达式都是由操作数(亦称运算对象).操作符(亦称运算 ...
- Aviator 表达式求值引擎开源框架
简介¶ Aviator是一个高性能.轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值.现在已经有很多开源可用的java表达式求值引擎,为什么还需要Avaitor呢? Aviato ...
- 【算法】E.W.Dijkstra算术表达式求值
算术表达式求值 我们要学习的一个栈的用例同时也是展示泛型的应用的一个经典例子,就是用来计算算术表达式的值,例如 ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) ) 如果将4乘以5,把3 ...
- lintcode 中等题:Evaluate Reverse Polish notation逆波兰表达式求值
题目 逆波兰表达式求值 在逆波兰表达法中,其有效的运算符号包括 +, -, *, / .每个运算对象可以是整数,也可以是另一个逆波兰计数表达. 样例 ["2", "1&q ...
- nyist0j 35 表达式求值
题目链接:表达式求值 该题以前做过但是WA了,今天终于把他解决了,各种悲剧啊,又是考虑不周到啊................... 所以贴出来纪念一下,并作为一个警示 /**** ps:注意当遇到 ...
- 函数嵌套 lisp表达式求值
问题 D: lisp表达式求值 时间限制: 1 Sec 内存限制: 128 MB提交: 105 解决: 43[提交][状态][讨论版] 题目描述 lisp是一种非常古老的计算机语言,是由约翰·麦卡 ...
- 第四届河南省ACM 表达式求值 栈
表达式求值 时间限制: 1 Sec 内存限制: 128 MB 提交: 14 解决: 7 [提交][状态][讨论版] 题目描述 Dr.Kong设计的机器人卡多掌握了加减法运算以后,最近又学会了一些简 ...
- C++之字符串表达式求值
关于字符串表达式求值,应该是程序猿们机试或者面试时候常见问题之一,昨天参加国内某IT的机试,压轴便为此题,今天抽空对其进行了研究. 算术表达式中最常见的表示法形式有 中缀.前缀和 后缀表示法.中缀表示 ...
随机推荐
- 【转】MyEclipse8.5集成Tomcat7时的启动错误:Exception in thread “main” java.lang.NoClassDefFoundError org/apache/commons/logging/LogFactory
http://www.cnblogs.com/newsouls/p/4021198.html 今天,安装Tomcat7.0.21后,单独用D:\apache-tomcat-7.0.21\bin\sta ...
- 经常使用的webservice接口
Web Service 一些对外公开的网络服务接口 2011-10-29 14:12 商业和贸易: 1.股票行情数据 WEB 服务(支持香港.深圳.上海基金.债券和股票:支持多股票同一时候查询) En ...
- JS知识点备忘
做前端久了,会发现很多比较杂的知识点,平时很少用到(往往在面试的时候经常见到),但是遇到的时候会很揪心...所以遇到的时候把它记录下来,但求有个印象,再次遇到时,可以在这里快速找到解决. 1.文档碎片 ...
- Android中定时器的3种实现方法
原文:http://blog.csdn.net/wulianghuan/article/details/8507221 在Android开发中,定时器一般有以下3种实现方法: 一.采用Handler与 ...
- android115 自定义控件
布局: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:to ...
- linux剪切拷贝
1.剪切 mv rename.sh ../rename.sh 把这个文件移到上一级目录下 mv rename.sh ./pic/rename.sh 把这个文件移到 当前目录下的pic目录下,并改名 ...
- mysql中的第三范式
※多表操作 (凡是多表,都要用到关联技术(把多表合并成一个新表): 左关联.右关联.内关联.还有一个外(全)关联,MySQL不支持,为考虑软件兼容,我们开发一般不用.) ※表与表之间的关系:1对1,1 ...
- How to solve GM MDI cannot complete the installation
Dear Joy, I have a problem using GM MDI diagnostic tool. When I installed it on my laptop, the tool ...
- hadoop学习记录(零)
这个博客开通快一年了,但是由于种种原因,始终没有能够养成定期更新的习惯. 最近完成了比赛的项目,向除了android开发以外再拓宽一下自己的技能树. 最近购买了<java8函数式编程>和& ...
- WebDriver: Getting it to play nicely with Xvfb
http://www.markhneedham.com/blog/2011/12/15/webdriver-getting-it-to-play-nicely-with-xvfb/ Thoughts ...