栈的应用--四则运算表达式求值(java语言)

栈的应用–四则运算表达式求值(java语言)

前言

在复习数据结构的过程中,采用单链表实现了栈Stack,具体功能有如下几个功能:判断其是否为空栈、输出栈的长度、入栈、出栈并且实现Iterable借口,可以采用Iterator遍历栈。在测试了栈之后,觉得应该将栈应用一下,于是在看书大话数据结构中,发现可以将栈应用到四则运算表达式求值中,这样我就想着去实现一下,想达到的目的是:当输入一个表达式,例如:9+(3-1)*3+10/2,可以得到其输出为20.

后缀(逆波兰)表示法定义

后缀表示法是由波兰的一位逻辑学家(名字太长,我就不写了)为了使用计算机解决四则运算问题而提出的,是一种不需要括号的后缀表达法,比如四则运算表达式9+(3-1)×3+10/2,其后缀表达式为931-3×+102/+,叫后缀的原因在于所有的符号都是在要运算数字的后面出现。
单链表实现栈的代码如下:

package ApplyStack;

import java.util.Iterator;

/**
 * 链表表头操作实现下压栈
 * 
 * @author 七分帅气
 * @date 2016.7.20
 * @param <Item>
 */
public class Stack<Item> implements Iterable<Item> {
    private Node first; // 表示链表的表头同时也表示栈顶
    private int N; // 链表的长度

    private class Node {
        Item data;
        Node next;

        public Node(Item data) {
            this.data = data;
        }
    }

    public boolean isEmpty() {
        return first == null;
    }

    public int size() {
        return N;
    }

    public void push(Item item) {
        Node oldFirst = first;
        first = new Node(item);
        first.next = oldFirst;
        N++;
    }

    public Item pop() {
        Item temp = first.data;
        first = first.next;
        N--;
        return temp;
    }

    @Override
    public Iterator<Item> iterator() {
        return new ListIterator();
    }

    private class ListIterator implements Iterator<Item> {
        private Node current = first;

        @Override
        public boolean hasNext() {
            return current != null;
        }

        @Override
        public Item next() {
            Item item = current.data;
            current = current.next;
            return item;
        }

        @Override
        public void remove() {

        }
    }
}

后缀表达式计算结果的规则

规则如下:从左到右遍历表达式的每个数字和符号,遇到是数字进栈,遇到是符号,就将处于栈顶的两个数字出栈进行运算,运算结果进栈,一直到最终获得结果(具体详见大话数据结构106页)。
java实现代码如下:

class PostToResult{
    private String post;   //中缀表达式转换得到的后缀表达式
    private Stack<Integer> stack;   //用于得到计算结果的栈

    public PostToResult(String post, Stack<Integer> stack) {
        this.post = post;
        this.stack = stack;
    }

    //由后缀表达式得到四则运算结果的实现过程
    public void operate(){
        String[] strArr = post.split(" ");
        for(int i = 0; i < strArr.length; i++){
            String temp = strArr[i];
            if(isDigital(temp)){
                stack.push(Integer.valueOf(temp));
            }else{
                int result = compute(temp);
                stack.push(result);
            }
        }
    }

    private int compute(String str){
        int re = 0;
        int m = stack.pop();
        int n = stack.pop();
        switch(str){
        case "+" :
            re = n + m;
            break;
        case "-" :
            re = n - m;
            break;
        case "*" :
            re = n * m;
            break;
        case "/" :
            re = n / m;
            break;
        default :
            break;
        }
        return re;
    }

    private boolean isDigital(String str){
        char[] chArr = str.toCharArray();
        int len = chArr.length;
        int count = 0;
        for(int i = 0; i < len; i++){
            if(chArr[i] >= '0' && chArr[i] <= '9')
                count++;
        }
        return count == len;
    }

    public int getResult() {
        return stack.pop();
    }
}

虽然后缀表达式有这样的优点,可是我们输入的是中缀表达式,所以需要将中缀表达式转换为后缀表达式。

中缀表达式转后缀表达式的规则

规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或者优先级不高于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止(具体详见大话数据结构108页)。
java实现代码如下:

package ApplyStack;
/**
 * 栈的应用:四则运算表达式求值
 * @author 七分帅气
 * @date 2016.7.20
 */
public class InfixToPost {
    private Stack<String> stack;  //中缀表达式转换为后缀表达式所需要的栈
    private String infix;    //输入的中缀表达式
    private String post = "";     //存储得到的后缀表达式

    //初始化构造器
    public InfixToPost(Stack<String> stack, String infix) {
        this.stack = stack;
        this.infix = infix;
    }

    /**
     * 
     * @param infix 输入的中缀表达式
     * @return  返回处理过后的中缀表达式,主要是在输入的中缀表达式加空格
     * 例如:输入的中缀表达式为:9+(3-1)*3+10/2
     *     输出的中缀表达式为:9 + ( 3 - 1 ) * 3 + 10 / 2
     */
    private String processInfix(String infix) {
        String result = "";
        for (int i = 0; i < infix.length() - 1; i++) {
            char temp1 = infix.charAt(i);
            char temp2 = infix.charAt(i + 1);
            if (isDigital(temp1) && isDigital(temp2)) {
                result += temp1;
            } else {
                result += temp1 + " ";
            }
        }
        result += infix.charAt(infix.length() - 1); // 将最后一个元素添加进去
        return result;
    }

    private boolean isDigital(char ch) {
        if (ch >= '0' && ch <= '9')
            return true;
        else
            return false;
    }

    //将前缀表达式转换为后缀表达式的处理过程
    public void process() {
        String[] strArr = processInfix(infix).split(" ");
        for (int i = 0; i < strArr.length; i++) {
            String str = strArr[i];
            switch (str) {
            case "+":
            case "-":
                getOperation(str, 1);
                break;
            case "*":
            case "/":
                getOperation(str, 2);
                break;
            case "(":
                stack.push(str);
                break;
            case ")":
                getParent();
                break;
            default:
                post += " " + str;
                break;
            }
        }
        // 数字全部输出后,需要输出栈中剩余的符号
        while (!stack.isEmpty()) {
            post += " " + stack.pop();
        }
    }

    private void getParent() {
        while (!stack.isEmpty()) {
            String top = stack.pop();
            if (top.equals("(")) {
                break;
            } else {
                post += " " + top;
            }
        }
    }

    private void getOperation(String str, int priority) {
        while (!stack.isEmpty()) {
            String top = stack.pop();
            if (top.equals("(")) {
                stack.push(top);
                break;
            } else {
                int priTop = getPriority(top);
                if (priTop < priority) {
                    stack.push(top);
                    break;
                } else {
                    post += " " + top;
                }
            }
        }
        stack.push(str);
    }

    private int getPriority(String str) {
        int pri = 0;
        if (str.equals("+") || str.equals("-")) {
            pri = 1;
        } else {
            pri = 2;
        }
        return pri;
    }

    public String getPost() {
        return post.trim();
    }

    public static void main(String[] args) {

        Stack<String> stack = new Stack<>();
        String input = "9+(3-1)*3+10/2";
        InfixToPost infix = new InfixToPost(stack, input);
        infix.process();

        String post = infix.getPost();
        Stack<Integer> stack_result = new Stack<>();
        PostToResult ptr = new PostToResult(post, stack_result);
        ptr.operate();
        System.out.println(ptr.getResult());
    }
}

以上我按照先把输入的中缀表达式字符串转换为后缀表达式字符串,然后通过后缀表达式字符串得到最后的计算结果。整个思路很清晰,但是在实现过程中遇到一个问题就是,当你用后缀表达式去得到结果的过程中,由于数字之间没有间隔,所以你无法区分数字是一位数还是两位数,就比如一开始给出的后缀表达式931-3*+102/+,你无法区分是9,3,1还是93,1或者9,13,无法判断。我的解决方法就是在一开始就对中缀表达式做预处理,将输入的中缀表达式符号与数字都用空格间隔开,这样做会使后续得到的后缀表达式能区分这种数字模糊性,于是顺理成章地得到最终正确的结果:20.

这是我的理解,如果有问题,希望大家指正。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值