用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的机试,压轴便为此题,今天抽空对其进行了研究. 算术表达式中最常见的表示法形式有 中缀.前缀和 后缀表示法.中缀表示 ...
随机推荐
- Spring集成Quartz定时任务框架介绍和Cron表达式详解
原文地址:http://www.cnblogs.com/obullxl/archive/2011/07/10/spring-quartz-cron-integration.html 在JavaEE系统 ...
- CustomViewWith_Image_Text_Video
CustomViewOfTextVideoImage.rar https://github.com/Grishu/CustomViewWith_Image_Text_Video
- SAP交货单过账自动生产采购订单、采购订单自动收货入库
公司间需要买卖操作,由于发货和收货都是同一批人在操作,为了减少业务人员的工作量,提高工作效率,特实现以上功能 1.增强实现:增强点为交货单过账成功时触发,在提交前触发,如果遇到不可预知问题,可能造成数 ...
- android127 zhihuibeijing 屏幕适配
## 屏幕适配 ## 加载不同分辨率的图片是根据手机的像素来加载不同分辨率文件夹下的图片. > 先在主流屏幕来发: *(分辨率和手机屏幕大小无关), 遵循原则: 不用AbsoluteLayout ...
- 搜索引擎的提示效果完整的JavaScript代码
function divShow() { <%--判断输入的是否为空 如果为空则隐藏div 如果不为空则显示div --%> if ($("#tbxSearchKeywords& ...
- C#_MVC_分页update
private static string getLinkHtml(UrlHelper urlHelper, bool useAjax, string ajaxSuccessFunction, str ...
- 使用VisualSVN Server搭建SVN服务器
工具: TortoiseSVN-1.8.4.24972-x64-svn-1.8.5(客户端) LanguagePack_1.8.4.24972-x64-zh_CN.msi Setup-Subversi ...
- ViewFlipper的简单使用实现图片轮播效果
/** * ViewFlipper: * 安卓系统自带的一个多页面管理控件,它可以实现子页面的自动切换 * 为ViewFlipper加入View: * (1)在layout布局文件静态导入子View ...
- Sqlserver的触发器的简单使用
1,触发器有两种 (1)After触发器(之后触发) 触发器有个好处:就是你之前有过什么操作他会将你的操作的数据信息完整的保存下来,比如你删过什么信息,如果用触发器,那么删除后就会显示两行受影响,那么 ...
- javascript中substring和substr方法
1.substring 方法 定义:用于提取字符串中介于两个指定下标之间的字符 语法:stringObject.substring(start,stop) 参数描述: start 必需.一个非负的整数 ...