《大话数据结构》-----栈的应用-----四则运算表达式求值--后缀表达式

运用技术

栈(这里用了顺序栈,就是数组存储的),ASCII码,中缀/后缀表达式

后缀表达式

对于四则运算,括号也是当中的一部分,先乘除后加减问题依然复杂,20实际50年代,波兰逻辑学家Jan Lukasiewicz想到一种不需要括号的后缀表达法*,我们也用逆波兰表示.

举个例子 9+(3-1)*3+10 /2叫中缀表达式,后缀表达式长这个样子: 9 3 1 - 3 * + 10 2 / +

先看看后缀表达式和栈之间怎么用的把

(书上东西步骤很详细也太多了,有请截图君上场)

后缀表达式-1
后缀表达式-2
后缀表达式-3
后缀表达式确实很神奇就解决掉了括号的问题

如何转换后缀表达式

接下来疑问很简单** 如何把中缀表达式转后缀表达式**,先看规则

从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;
若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减),则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式位置.

9+(3-1)*3+10 /2 ===>> 9 3 1 - 3 * + 10 2 / +
嗯…知道说了也看不懂,还是截图君上场

转换-1
转换-2
第6步这里,经过实践和一步步敲,得出结论:
第六步第一句话和第二句的写反了
即应该是:紧接着是符号…"*"进栈. 接着是数字3…- 3.
为什么?因为中缀表达式是9+(3-1)*3+10 /2这个呀,明显*在前
转换-3
转换-4
转换-5
9+(3-1)*3+10 /2 ===>> 9 3 1 - 3 * + 10 2 / +

代码实现


package ***;
/**
 * @Author: wsh
 */
public class StackTest {


    public static void main(String[] args) {

        ArrStackList conver = conver("9+(3-1)*3+6/2");
        //目前conver是一个个push进去的
        //是倒序,所以再创建一个栈,转换"正过来"
        ArrStackList order = new ArrStackList();
        int top = conver.arrStack.top;
        while (top != -1) {
            order.push(conver.pop());
            top = conver.arrStack.top;
        }
        order.out("后缀表达式:");
        System.out.println("结果是" + compute(order));


    }

    public static int compute(ArrStackList order) {
        //临时用一个栈中转
        ArrStackList arr = new ArrStackList();
        arr.init(new String[]{});

        do {
            int pop = order.pop();
            //含运算法则 42 * 43 + 45- 47 /
            if (pop < 48) {
                int one = (char)(arr.pop());
                int two = (char)(arr.pop());
                int operator =   operator(pop, two, one);
                arr.push(operator);
            }else{
                arr.push( Integer.parseInt(String.valueOf((char)pop)));
            }
        } while (order.arrStack.top !=-1);
        return arr.pop();

    }

    /**
     * 四则运算
     */
    public static int operator(int o, int op1, int op2) {
        int res=0;
        //ASCII码 42 * 43 + 45- 47 /
        switch (o) {
            case 42: res= op1*op2;break;
            case 43: res= op1+op2;break;
            case 45: res= op1-op2;break;
            case 47: res= op1/op2;break;
        }
        return res;
    }


    /**
     * 中缀转后缀
     * 9+(3-1)*3+6/2 转化为 9 3 1 - 3 * + 6 2 / +
     */
    public static ArrStackList conver(String data) {
        //用来存储,最后返回
        ArrStackList result = new ArrStackList();
        result.init(new String[]{});

        //中间处理
        ArrStackList arrStackList = new ArrStackList();
        arrStackList.init(new String[]{});
        char[] chars = data.toCharArray();
        for (char d : chars) {
            //ASCII码 42 * 43 + 45- 47 /  40(  41)
            switch (d) {
                case 42:
                case 47: {
                    int pop1 = arrStackList.pop();
                    //若有+ - 优先级低,则* 进栈
                    if (pop1 != -1 && (pop1 == 43 || pop1 == 45)) {
                        arrStackList.push(pop1);
                        arrStackList.push(d);
                    } else {
                        result.push(d);
                    }

                    break;
                }
                case 43:
                case 45: {
                    int out = arrStackList.pop();
                    if (out != -1 && (out == 42 || out == 43)) {
                        while (out != -1) {
                            result.push(out);
                            out = arrStackList.pop();
                        }
                        arrStackList.push(d);
                    } else {
                        if (out != -1) {
                            arrStackList.push(out);
                        }
                        arrStackList.push(d);
                    }

                    break;
                }
                //左括号直接进栈
                case 40:
                    arrStackList.push(d);
                    break;
                case 41: {
                    int pop = arrStackList.pop();
                    while (pop != 40) {
                        result.push(pop);
                        pop = arrStackList.pop();
                    }
                    break;
                }
                default:
                    result.push(d);
            }
        }
        int out = arrStackList.pop();
        while (out != -1) {
            result.push(out);
            out = arrStackList.pop();
        }
        return result;


    }

}

class ArrStackList {
    ArrStack arrStack = new ArrStack();

    public int pop() {

        if (arrStack.top == -1) {
            System.out.println("栈已空");
            return -1;
        }
        int datum = arrStack.data[arrStack.top];
        arrStack.data[arrStack.top] = 0;
        arrStack.top--;
        return datum;

    }

    public void push(int value) {
        if (arrStack.top + 1 == arrStack.data.length) {
            System.out.println("入栈失败,已满");
            return;
        }
        arrStack.top++;
        arrStack.data[arrStack.top] = value;

    }

    public void init(String[] data) {

        for (int i = 0; i < data.length; ) {
            int value = Integer.parseInt(data[i]);
            arrStack.data[i] = value;
            arrStack.top = i++;
        }
        System.out.println();
    }

    public void out(String str) {
        System.out.println(str);
        int[] data = arrStack.data;
        int top = arrStack.top;
        for (int i = top; i >= 0; i--) {
            System.out.print((char) data[i] + " ");
        }
        System.out.println("\n======");
    }
}

class ArrStack {
    private int MaxLength = 20;
    public int[] data = new int[MaxLength];
    public int top = -1;
}

输出


栈已空
栈已空
栈已空
正序内容:
9 3 1 - 3 * + 6 2 / + 
======

结果是18

这里的堆栈已空,返回了-1 其实是不同的位置,while在循环中判断-1使用的,所以不受影响

缺点和不足

  • 运算长度数少,代码数组初始化20个,注定不能运算太长的四则运算,不然后缀表达式周转完以后太长了,就塞不下了
  • 运算数值小,在判断运算法则使用char类型, Stringchar类型,注定两位数要拆开(10就被算成1和0两个char),达到效果不一致,所以书中是有个10,我换成了6 😃
  • 运算逻辑繁琐,因为默认是int类型,里面存放了char的运算符又放了char的数值,采用ASCII码方式,(42 * 43 + 45- 47 /),在取出计算时,再根据范围判断运算和数字
  • 运算类型转换过多,若是运算符取出两个char类型数字转int加减乘除,若是数值需要Integer.parseInt(String.valueOf((char)pop))pop=51转成int类型数值3,以便后续运算

收获和总结

  • 本来以为写的是后缀,发现其实还有运算,相比运算比后缀复杂一些.同时操作两个栈进和出
  • 竟然char转int类型还要搜索,真是逊Integer.parseInt(String.valueOf((char)pop)
  • 四则运算那边,自己一开始写的是在case里面,差不多最后才拿出来,给自己带来很多无用功.嗯…不会偷懒(抽取)的程序员不是好程序员

拜了个拜,下个知识点搞起.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值