《算法(第四版)》 习题:1.3.10 将算术表达式由中序表达式转为后序表达式

关于逆波兰表示法

逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法),是一种是由波兰数学家扬·武卡谢维奇1920年引入的数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。
逆波兰结构由弗里德里希·鲍尔(Friedrich L. Bauer)和艾兹格·迪科斯彻在1960年代早期提议用于表达式求值,以利用堆栈结构和减少计算机内存访问。逆波兰记法和相应的算法由澳大利亚哲学家、计算机学家查尔斯·汉布林(Charles Hamblin)在1960年代中期扩充。

举例:

中序表达式:
( 2 + ( ( 3 + 4 ) * ( 5 * 6 ) ) )
后序表达式:
2 3 4 + 5 6 * * +

规律:

  • 中序和后序表达式中的数字顺序不变,都是2 3 4 5 6;
  • 后序表达式中没有括号
  • 运算符的顺序与运算时的优先级相关;

分析:

  • (3 + 4): 3 4 +;
  • (5 * 6):5 6 * ;
  • ( ( 3 + 4 ) * ( 5 * 6 ) ): 3 4 + 5 6 * *;
  • ( 2 + ( ( 3 + 4 ) * ( 5 * 6 ) ) ): 2 3 4 + 5 6 * * +;
  • 也就是:2 ((3 4 +)(5 6 *)*)+;

解题思路:
可以参考习题:1.3.9,需要用到双栈法的核心思想。

  • 遇到数字直接打印,或顺序保存到字符串中;
  • 遇到左括号“(”直接跳过;
  • 遇到运算符就压入栈顶;
  • 遇到“)”时,每当遇到一个“)”,就将弹出一个运算符,打印出来,或者接到字符串后面;
  • 结果不涉及左右括号,所以不要费心思处理括号(太复杂),应该把右括号当做标志,作为操作栈的时机,这也是“双栈法”的精髓之一。

代码:
摘自《算法(第四版)》,我没做出来。

package chapter1_3;

import edu.princeton.cs.algs4.Stack;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;

/**
 * Compilation:  javac InfixToPostfix.java
 *  Execution:    java InfixToPostFix
 *  Dependencies: Stack.java StdIn.java StdOut.java
 *
 *  Reads in an infix expression and outputs an equivalent postfix
 *  expression.
 *
 *  Windows users: replace [Ctrl-d] with [Ctrl-z] to signify end of file.
 *
 *  % java InfixToPostfix
 *  ( 2 + ( ( 3 + 4 ) * ( 5 * 6 ) ) )
 *  [Ctrl-d]
 *  2 3 4 + 5 6 * * +
 *
 *  % java InfixToPostfix | java EvaluatePostfix
 *  ( 2 + ( ( 3 + 4 ) * ( 5 * 6 ) ) )
 *  [Ctrl-d]
 *  212
 */

public class InfixToPostfix {
    public static void main(String[] args) {
        Stack<String> stack = new Stack<String>();
        while (!StdIn.isEmpty()) {
            String s = StdIn.readString();
            if      (s.equals("+")) stack.push(s);
            else if (s.equals("*")) stack.push(s);
            else if (s.equals(")")) StdOut.print(stack.pop() + " ");
            else if (s.equals("(")) StdOut.print("");
            else                    StdOut.print(s + " ");
        }
        StdOut.println();
    }
}

如何根据后序表达式运算:

public static void main(String[] args) {

        Stack<Double> vals = new Stack<>();

        while (!StdIn.isEmpty()) {
            String s = StdIn.readString();

            if      (s.equals("+")) vals.push(vals.pop() + vals.pop());
            else if (s.equals("-")) vals.push(vals.pop() - vals.pop());
            else if (s.equals("*")) vals.push(vals.pop() * vals.pop());
            else if (s.equals("/")) vals.push(vals.pop() / vals.pop());
            else                    vals.push(Double.parseDouble(s));
        }

        StdOut.println("result = " + vals.pop());
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值