zoukankan      html  css  js  c++  java
  • 使用堆栈结构进行字符串表达式("7*2-5*3-3+6/3")的计算

    问题:

    给定字符串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.

     1 /**
     2  * 使用数组模拟栈
     3  * @author SCOTT
     4  *
     5  */
     6 public class MyStack {
     7     
     8     private int top = -1; //指向栈顶的索引
     9     private int maxSize = 100; //栈所能存储的最大个数
    10     private Object[] array = new Object[maxSize];    //数组
    11     
    12     /**
    13      * 加入一个元素
    14      * @param val
    15      */
    16     public void push(Object val){
    17         if(top == maxSize - 1){
    18             System.out.println("栈满");
    19             return;
    20         }
    21         array[++top] = val;
    22     }
    23     
    24     /**
    25      * 弹出一个元素
    26      * @return
    27      */
    28     public Object pop(){
    29         if(top == -1){
    30             System.out.println("栈空");
    31             return null;
    32         }
    33         return array[top--];
    34     }
    35     
    36     /**
    37      * 遍历
    38      */
    39     public void toList(){
    40         for(int i=top;i>-1;i--){
    41             System.out.println(i+"="+array[i]);
    42         }
    43     }
    44     
    45     /**
    46      * 判断栈是否为空
    47      * @return
    48      */
    49     public boolean isEmpty(){
    50         if(top == -1)
    51             return true;
    52         return false;
    53     }
    54     
    55     /**
    56      * 获取栈顶的元素,跟pop()方法的区别在于:pop()方法的top索引会减1,而getTop不会
    57      */
    58     public Object getTop(){
    59         if(top == -1)
    60             return null;
    61         return array[top];
    62     }
    63 }

    对栈有了了解之后,就可以计算: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.计算完毕后,在数栈会存在一个唯一的值,这个值就是我们需要的结果。

    具体实现:

      1 /**
      2  * 计算字符串表达式
      3  * @author SCOTT
      4  *
      5  */
      6 public class StackApp {
      7 
      8     public static void main(String[] args) {
      9         
     10         String str = "7*2-5*3-3+6/3";
     11         //str的索引,默认指向第一位
     12         int index = 0;
     13         //用于拼接连续数字
     14         String tempStr = "";
     15         //数栈
     16         MyStack numStatck = new MyStack();
     17         //符号栈
     18         MyStack operStatck = new MyStack();
     19         
     20         while(true){
     21             char ch = str.charAt(index);
     22             if(isNum(ch)){
     23                 //先进行拼接,满足条件,在放入数栈
     24                 tempStr += ch;
     25                 //如果到了字符串末尾,或者下一位是符号,则放入数栈
     26                 if(index == str.length() - 1 || !isNum(str.charAt(index+1))){
     27                     numStatck.push(tempStr);
     28                 }
     29             }else{
     30                 tempStr = "";
     31                 if(operStatck.isEmpty()){
     32                     //如果符号栈为空,则直接将运算符放入符号栈
     33                     operStatck.push(ch);
     34                 }else{
     35                     //循环判断:如果当前运算符的级别<=栈顶运算符的级别,则计算
     36                     while(!operStatck.isEmpty() && getLevel(ch+"") <= getLevel(operStatck.getTop().toString())){
     37                         int res = calculate(numStatck, operStatck);
     38                         //将res入数栈
     39                         numStatck.push(res);
     40                     }
     41                     //将符号放入符号栈
     42                     operStatck.push(ch);
     43                 }
     44             }
     45             
     46             index++;
     47             //判断条件,break
     48             if(index == str.length())
     49                 break;
     50         }
     51         
     52         //遍历完成后,进行计算
     53         while(!operStatck.isEmpty()){
     54             int res = calculate(numStatck, operStatck);
     55             //将运算结果放入数栈
     56             numStatck.push(res);
     57         }
     58         
     59         //最后在数栈肯定会存在唯一的结果
     60         System.out.println(numStatck.pop());//-2
     61         
     62     }
     63     
     64     /**
     65      * 判断截取位,是否是数字
     66      * @param ch
     67      * @return
     68      */
     69     public static boolean isNum(char ch){
     70         if(ch == '+' || ch == '-' || ch == '*' || ch == '/')
     71             return false;
     72         return true;
     73     }
     74     
     75     /**
     76      * *和/级别为1,+和-级别为0
     77      * @return
     78      */
     79     public static int getLevel(String oper){
     80         if("*".equals(oper) || "/".equals(oper))
     81             return 1;
     82         return 0;
     83     }
     84     
     85     /**
     86      * 计算结果://从数栈中取出两位,从符号栈中取出一位
     87      * @param numStatck
     88      * @param operStatck
     89      * @return
     90      */
     91     public static int calculate(MyStack numStatck, MyStack operStatck){
     92         int num1 = 0;
     93         if(numStatck.getTop() != null)
     94             num1 = Integer.parseInt(numStatck.pop().toString());
     95         int num2 = 0;
     96         if(numStatck.getTop() != null){
     97             num2 = Integer.parseInt(numStatck.pop().toString());
     98         }
     99         String str = "";
    100         if(operStatck.getTop() != null){
    101             str = operStatck.pop().toString();
    102         }
    103         
    104         int res = 0;
    105         switch (str.charAt(0)) {
    106             case '+':
    107                 res = num1 + num2;
    108                 break;
    109             case '-':
    110                 res = num2 - num1;//注意顺序,栈是先入后出的结构
    111                 break;
    112             case '*':
    113                 res = num1 * num2;
    114                 break;
    115             case '/':
    116                 res = num2 / num1;//注意顺序,栈是先入后出的结构
    117                 break;
    118             default:
    119                 throw new RuntimeException("运算符不正确");
    120         }
    121         
    122         return res;
    123     }
    124 }

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

  • 相关阅读:
    myeclipse8.6注册码
    hibernate用注解(annotation)配置sequence
    MyEclipse注释配置
    JAVA 单选样式编写
    .Net中的几种异步模式
    C#并发编程——并发编程技术
    《CLR via C#》之线程处理——任务调度器
    《CLR via C#》之线程处理——线程池与任务
    《CLR via C#》之线程处理——协作式取消和超时
    《CLR via C#》之线程处理——线程基础
  • 原文地址:https://www.cnblogs.com/myCodingSky/p/3803938.html
Copyright © 2011-2022 走看看