• 前序表达式 中序表达式 后序表达式


    中序表达式:

    中序表达式就是我们日常使用的表达式,由左往右阅读,结构清晰,但需要括号改变优先级,对计算机不友好

    eg: (1+4)*3+10/5

    前序表达式(波兰表示法Polish notation,或波兰记法):

    一种逻辑算术代数表示方法,其特点是操作符置于操作数的前面,如果操作符的元数(arity)是固定的,则语法上不需要括号仍然能被无歧义地解析,不需要括号来改变优先级,未推广使用。

    eg:

    中序表达式:(1 + 4) * 3 + 10 / 5 
    
    前序表达式:  + * + 1 4 3  / 10 5 
    
    
    前序表达式的运算:
        
    eg:
        + * + 1 4 3  / 6 5 
    
    运算: + 1 4  =>   1 + 4 = 5  
          
          * 5 3  =>  5 * 3 = 15
         
    新前序: + 15 / 10 5 
        
        / 10 5  =>  10 / 5 =2
        
    新前序:  + 15 2
            
          =>  15 + 2 = 17  

     

    后序表达式(逆波兰表示法Reverse Polish notationRPN,或逆波兰记法):

    所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级,使用广泛。艾兹格·迪科斯彻引入了调度场算法,用于将中缀表达式转换为后缀形式。因其操作类似于火车编组场而得名。 大多数操作符优先级解析器(解析器用简单的查表操作即可实现,优先级表由开发者自己定制,在不同的应用场景中,开发者可自由改变操作符的优先级)能转换为处理后缀表达式,实际中,一般构造抽象语法树,树的后序遍历即为逆波兰记法。

    eg:

    中序表达式:(1 + 4) * 3 + 10 / 5 
    
    后序表达式: 1 4 + 3 *  10 5 / +
    
    
    后序表达式的运算:
        
    eg:
        1 4 + 3 *  10 5 / +
    
    运算: 1 4 +  =>   1 + 4 = 5  
          
          5 3 *  =>  5 * 3 = 15
         
    新后序:  15 / 10 5 + 
        
         10 5  / =>  10 / 5 =2
        
    新后序:  15 2 +
            
          =>  15 + 2 = 17  

    中序转后序(调度场算法)

    1. 创建一个队列和一个操作数栈
    2. 遇到操作数则送入队列
    3. 遇到操作符则送入栈
    4. 当碰到与栈顶同优先级的操作符,则将栈顶的操作符取出,送入队列,并将新操作符压入栈中
    5. 遇到” )“括号则将栈内从”( “到” )“的所有操作符全部取出送入队列
    6. 表达式分类完成后,先输出队列内容,再输出栈内容,前者+后者便是后序表达式

    实现代码(Java版):

    public static String InfixToPostfix(String s) {
    		
        Stack<Character> stack = new Stack<Character>();
        Queue<Character> queue = new Queue<Character>();
        
        Character s1 = ' ';
        char peeks = ' '; // 栈顶元素
    
        for (int i = 0; i < s.length(); i++) {
    
    	// 如果是操作数,则送入操作数队列
    	if (s.charAt(i) >= 48 && s.charAt(i) <= 57) {
    	    queue.enqueue(s.charAt(i) );
    	    continue;
    	  }
    
          // 如果碰到右括号则遍历栈,并送入队列,直到碰到"("
    	if (s.charAt(i) == ')') {
    	    s1 = stack.pop();
    	    while (s1 != '(' ) {
    		queue.enqueue(s1);
    		s1 = stack.pop();
    	     }
    	continue;
    	}
    			
           
           // 如果出现同优先级的运算符, 则将栈顶元素送入队列中 同时新运算符送入栈内
        
    	if ( (s.charAt(i) == '/' || s.charAt(i) == '*') &&
                 (peeks == '*' || peeks == '/') ) {
    	
                queue.enqueue(stack.pop());
    	    stack.push(s.charAt(i));
    	    peeks=s.charAt(i);
    	}
    	
            // 剩下的普通情况下的操作符,送入操作符栈
    	{
    	    stack.push(s.charAt(i) );
    	    peeks = s.charAt(i);	
    	}
    
        }
    
        s = " ";// 初始化s来接收表达式
    
        //接收队列的值
        do {
    	s += queue.dequeue() +" ";
        } while (!queue.isEmpty());
    
        //接受栈的值		
        do {
    	s += stack.pop() + "  ";
        } while (!stack.isEmpty());
    		
        return s;
    }
    
  • 相关阅读:
    Linux C/C++编程之(三)常用命令之文件处理命令
    linux下查看activiti流程图乱码
    基于区块链的自主身份和可信声明
    数字证书PKI原理
    Linux C/C++编程之(二)常用命令之目录处理命令
    Linux C/C++编程之(一)VMware 虚拟机安装Ubuntu16.04 图解
    移动端专项测试-内存泄漏
    centos7 netstat命令使用场景 杂记
    《java入门第一季》之面向对象(构造方法)
    《java入门第一季》之面向对象this关键字
  • 原文地址:https://www.cnblogs.com/jeasion/p/10758386.html
Copyright © 2020-2023  润新知