问题:

给定字符串String str = "7*2-5*3-3+6/3", 求出字符串里面表达式的结果?

像javascript有自带的eval()方法,可以直接计算。但java或其它语言,API并没有提供直接计算的方法(可能是我孤陋寡闻),这时就需要我们自己写方法实现了。

栈:

要实现上述功能,需要用到堆栈的概念,

栈是一种特殊的串行形式的数据结构,它的特殊在于,只能在队列的一端进行输入和输出,因此按照"先入后出"的原理运行。就像一个盒子,先放进的东西在下面,后面放进的东西反而在上面。如上图,栈可以看成是一个"倒立的数组"。有一个top索引,永远指向最上面一个节点。当加入一个元素时,top往上移一位。取走一个元素时,top往下移一位。当栈为空时,top指向栈的下方,top=-1.

根据上面的结构,我们可以自定义一个栈,并实现入栈(push)和弹栈(pop)两个方法:

1.入栈:将数据放入堆栈的顶端,top索引+1.

2.弹栈:将栈顶数据输出,top索引-1.

 /**
* 使用数组模拟栈
* @author SCOTT
*
*/
public class MyStack { private int top = -1; //指向栈顶的索引
private int maxSize = 100; //栈所能存储的最大个数
private Object[] array = new Object[maxSize]; //数组 /**
* 加入一个元素
* @param val
*/
public void push(Object val){
if(top == maxSize - 1){
System.out.println("栈满");
return;
}
array[++top] = val;
} /**
* 弹出一个元素
* @return
*/
public Object pop(){
if(top == -1){
System.out.println("栈空");
return null;
}
return array[top--];
} /**
* 遍历
*/
public void toList(){
for(int i=top;i>-1;i--){
System.out.println(i+"="+array[i]);
}
} /**
* 判断栈是否为空
* @return
*/
public boolean isEmpty(){
if(top == -1)
return true;
return false;
} /**
* 获取栈顶的元素,跟pop()方法的区别在于:pop()方法的top索引会减1,而getTop不会
*/
public Object getTop(){
if(top == -1)
return null;
return array[top];
}
}

对栈有了了解之后,就可以计算:String str = "7*2-5*3-3+6/3".

思路:

1.初始化两个栈,一个数栈(存放表达式中的数字),一个符号栈(用来存储表达式中的符号).

2.遍历字符串str,将字符一个个取出进行判断,假定用ch存储取出的字符.

  2.1.如果ch为数字,直接将数字放入数栈(这是一种抽象的说法,如果存在像700这种两位以上的数字,需要自己拼接,然后再一起入栈,只占一个位置).

  2.2.如果ch为符号.

    2.2.1.如果符号栈为空,就直接将符号放入符号栈.

   2.2.2.如果符号栈不为空, 就判断当前符号(ch)的运算级别跟符号栈栈顶的符号(放在符号栈最上面的一个运算符)运算级别谁大谁小?

      2.2.2.1 循环判断,如果当前符号(ch)的优先级<=符号栈栈顶运算符的优先级,则进行计算。计算方式:从数栈中弹出两个数,和符号栈弹出一个符号,进行计算并得到结果res,将res再放入数栈。直到当前运算符的优先级>符号栈栈顶运算符的优先级为止。

      2.2.2.2 将当前符号(ch)加入符号栈.

3.到此,已经将字符串str遍历完毕。然后再将数栈和符号栈的数据取出进行计算。计算的方式:先从数栈取出两个数,再从符号栈弹出符号,计算并得到结果res,然后将res放入数栈。依次循环,直到符号栈为空为止。

4.计算完毕后,在数栈会存在一个唯一的值,这个值就是我们需要的结果。

具体实现:

 /**
* 计算字符串表达式
* @author SCOTT
*
*/
public class StackApp { public static void main(String[] args) { String str = "7*2-5*3-3+6/3";
//str的索引,默认指向第一位
int index = 0;
//用于拼接连续数字
String tempStr = "";
//数栈
MyStack numStatck = new MyStack();
//符号栈
MyStack operStatck = new MyStack(); while(true){
char ch = str.charAt(index);
if(isNum(ch)){
//先进行拼接,满足条件,在放入数栈
tempStr += ch;
//如果到了字符串末尾,或者下一位是符号,则放入数栈
if(index == str.length() - 1 || !isNum(str.charAt(index+1))){
numStatck.push(tempStr);
}
}else{
tempStr = "";
if(operStatck.isEmpty()){
//如果符号栈为空,则直接将运算符放入符号栈
operStatck.push(ch);
}else{
//循环判断:如果当前运算符的级别<=栈顶运算符的级别,则计算
while(!operStatck.isEmpty() && getLevel(ch+"") <= getLevel(operStatck.getTop().toString())){
int res = calculate(numStatck, operStatck);
//将res入数栈
numStatck.push(res);
}
//将符号放入符号栈
operStatck.push(ch);
}
} index++;
//判断条件,break
if(index == str.length())
break;
} //遍历完成后,进行计算
while(!operStatck.isEmpty()){
int res = calculate(numStatck, operStatck);
//将运算结果放入数栈
numStatck.push(res);
} //最后在数栈肯定会存在唯一的结果
System.out.println(numStatck.pop());//-2 } /**
* 判断截取位,是否是数字
* @param ch
* @return
*/
public static boolean isNum(char ch){
if(ch == '+' || ch == '-' || ch == '*' || ch == '/')
return false;
return true;
} /**
* *和/级别为1,+和-级别为0
* @return
*/
public static int getLevel(String oper){
if("*".equals(oper) || "/".equals(oper))
return 1;
return 0;
} /**
* 计算结果://从数栈中取出两位,从符号栈中取出一位
* @param numStatck
* @param operStatck
* @return
*/
public static int calculate(MyStack numStatck, MyStack operStatck){
int num1 = 0;
if(numStatck.getTop() != null)
num1 = Integer.parseInt(numStatck.pop().toString());
int num2 = 0;
if(numStatck.getTop() != null){
num2 = Integer.parseInt(numStatck.pop().toString());
}
String str = "";
if(operStatck.getTop() != null){
str = operStatck.pop().toString();
} int res = 0;
switch (str.charAt(0)) {
case '+':
res = num1 + num2;
break;
case '-':
res = num2 - num1;//注意顺序,栈是先入后出的结构
break;
case '*':
res = num1 * num2;
break;
case '/':
res = num2 / num1;//注意顺序,栈是先入后出的结构
break;
default:
throw new RuntimeException("运算符不正确");
} return res;
}
}

上面的步骤,并没有实现带有()、[]、{}的复杂运算,还有待后续研究.

使用堆栈结构进行字符串表达式("7*2-5*3-3+6/3")的计算的更多相关文章

  1. C++之字符串表达式求值

    关于字符串表达式求值,应该是程序猿们机试或者面试时候常见问题之一,昨天参加国内某IT的机试,压轴便为此题,今天抽空对其进行了研究. 算术表达式中最常见的表示法形式有 中缀.前缀和 后缀表示法.中缀表示 ...

  2. Python内置数据结构之字符串str

    1. 数据结构回顾 所有标准序列操作(索引.切片.乘法.成员资格检查.长度.最小值和最大值)都适用于字符串,但是字符串是不可变序列,因此所有的元素赋值和切片赋值都是非法的. >>> ...

  3. javascript使用栈结构将中缀表达式转换为后缀表达式并计算值

    1.概念 你可能听说过表达式,a+b,a+b*c这些,但是前缀表达式,前缀记法,中缀表达式,波兰式,后缀表达式,后缀记法,逆波兰式这些都是也是表达式. a+b,a+b*c这些看上去比较正常的是中缀表达 ...

  4. 字符串表达式String Expressions

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  5. [SAP ABAP开发技术总结]字符串表达式String Expressions

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  6. CF552E 字符串 表达式求值

    http://codeforces.com/contest/552/problem/E E. Vanya and Brackets time limit per test 1 second memor ...

  7. Function:html结构转字符串形式显示

    //Html结构转字符串形式显示 支持<br>换行 function ToHtmlString(htmlStr) { return toTXT(htmlStr).replace(/\&am ...

  8. PHP 实现字符串表达式计算

    什么是字符串表达式?即,将我们常见的表达式文本写到了字符串中,如:"$age >= 20",$age 的值是动态的整型变量. 什么是字符串表达式计算?即,我们需要一段程序来执 ...

  9. 在C#开发中使用第三方组件LambdaParser、DynamicExpresso、Z.Expressions,实现动态解析/求值字符串表达式

    在进行项目开发的时候,刚好需要用到对字符串表达式进行求值的处理场景,因此寻找了几个符合要求的第三方组件LambdaParser.DynamicExpresso.Z.Expressions,它们各自功能 ...

随机推荐

  1. .NET基础拾遗(8)ADO.NET与数据库开发基础

    1.1 ADO.NET支持哪几种数据源? ① System.Data.SqlClient .NET程序员最常用的了.通过OLEDB或者ODBC都可以访问,但是SqlClient下的组件直接针对MSSQ ...

  2. SQL每个用户最后的一条记录

    SELECT [ID] ,[UserID] ,[StartDate] ,[EndDate] ,[CreateUser] ,[CreateDate] ,[LastEditUser] ,[LastEdit ...

  3. DNN7网站系统需求及部署指南详解

    此安装指南适用于DNN6.x和DNN7.x在本地测试及主机的安装.最近QQ群里不少朋友问我关于DotNetNuke的安装和运行的问题. 为了让大家更清楚地了解DNN的安装方式,我在这里对DotNetN ...

  4. Oracle除去换行符的方法

    Oracle除去换行符的方法   很多数据存进数据库后,可能需要将整条数据取出,并用特殊 符号分割,而且整条数据必须是处于一行,如此,如果数据出现 换行的情况,那么读取时就有问题.     这个时候就 ...

  5. java对像序列化

    package cn.stat.p2.demo; import java.io.FileInputStream; import java.io.FileNotFoundException; impor ...

  6. nginx_http核心模块(二)

    对一些常用的配置项做一些解释:详细请看官方文档:http://nginx.org/en/docs/http/ngx_http_core_module.html 1. alias Syntax: ali ...

  7. Java并发编程与技术内幕:线程池深入理解

    摘要: 本文主要讲了Java当中的线程池的使用方法.注意事项及其实现源码实现原理,并辅以实例加以说明,对加深Java线程池的理解有很大的帮助. 首先,讲讲什么是线程池?照笔者的简单理解,其实就是一组线 ...

  8. [转]关于Chrome不能登录和同步的解决方法

    原帖地址:http://tieba.baidu.com/p/3086127792?pn=1 在本机的hosts文件(C:\Windows\System32\drivers\etc)里加入下面内容: # ...

  9. destoon实现调用热门关键字的方法

    本文所述的destoon调用热门关键字的方法是根据数据库里面的保存的搜索的关键字来显示的.每个模块下面都有各自的关键字下面是调用的标签: ? 1 <!--{tag("moduleid= ...

  10. Python 学习日记(第四周)

    set数据类型 先用一行代码来说明一下 #!/usr/bin/env python s2={} s = {33,12,33,32121} for i in s: print(i) print(type ...