算法学习:完整的表达式括号匹配算法

《算法4》课后题目中,有一道题:编写一道程序,从标准输入得到一个缺少左括号的表达式并打印出补全括号之后的中序表达式。例如,给定输入: 1 + 2 ) * 3 - 4 ) * 5 - 6 ) ) ) 你的程序应该输出: ((1 + 2) * ((3 - 4) * (5 - 6)))

网上有关这道题目,实现的基本都是左括号匹配,对于右括号匹配,未能找到答案。如果考虑操作符优先级的话,题目给出的预期结果,也只是其中一种结果,还有其他的匹配结果。自己实现一个算法,匹配括号,带操作符优先级。代码如下,供大家学习参考。

package com.sylar;

import java.util.Stack;

/**
 * 表达式括号匹配
 *
 */
public class ExpressBracketMatch {

    //操作符优先级定义
    final static String OPERATOR_PRIORITY[] = new String[]{"+-", "*/", "^"};

    /**
     * 表达式匹配
     *
     * @param express 表达式参数,可以包含空格
     * @return
     */
    public static String match(String express) {
        String newExpress = express.replaceAll(" ", "");
        Stack<String> operStack = new Stack<>();
        Stack<String> dataStack = new Stack<>();

        for (int i = 0; i < newExpress.length(); i++) {
            String ss = String.valueOf( newExpress.charAt(i) );
            if (isDigit(ss.charAt(0))) {
                //处理数字的情况
                dataStack.push(ss);
            } else if ( isOperator(ss.charAt(0) ) ) {
                //处理操作符的情况
                if( operStack.isEmpty() ) {
                    operStack.push(ss);
                }else {
                    //操作符优先级处理
                    doMatch( dataStack, operStack, ss.charAt(0) );
                }
            } else if( "(".equals(ss) ) {
                operStack.push(ss);
            } else {
                // 处理右括号的情况
                doMatch(dataStack, operStack);
            }
        }

        while (operStack.size() > 0) {
            String preOp = operStack.peek();
            if( "(".equals(preOp) ){
                operStack.pop();
                continue;
            }
            doMatch(dataStack, operStack);
        }

        return dataStack.pop();
    }

    /**
     * 匹配括号
     *
     * @param dataStack 操作数栈
     * @param operStack 操作符栈
     */
    private static void doMatch(Stack<String> dataStack, Stack<String> operStack ){
        if(operStack.isEmpty()){
            return;
        }

        String right = dataStack.pop();
        String left = dataStack.pop();
        String opt = operStack.pop();
        String bracket = ")";
        if( !operStack.isEmpty() && operStack.peek().equals(")") ){
            operStack.pop();
        }
        dataStack.push("(" + left + opt + right + bracket);
    }

    /**
     * 匹配括号,处理优先级
     *
     * @param dataStack 操作数栈
     * @param operStack 操作符栈
     * @param curOper 当前操作符
     */
    private static void doMatch(Stack<String> dataStack, Stack<String> operStack, char curOper ){
        if( operStack.isEmpty() ){
            operStack.push( String.valueOf(curOper) );
            return;
        }

        String preOp = operStack.peek();
        if ( preOp.equals("(") ) {
            operStack.pop();
            operStack.push( String.valueOf(curOper) );
            return;
        }

        if (getPriority(preOp.charAt(0)) >= getPriority(curOper)) {
            String right = dataStack.pop();
            String left = dataStack.pop();
            String opt = operStack.pop();
            String bracket = ")";
            if ( !operStack.isEmpty() && operStack.peek().equals(")") ) {
                operStack.pop();
            }
            dataStack.push("(" + left + opt + right + bracket);
            doMatch(dataStack, operStack, curOper);
        }else{
            operStack.push(String.valueOf(curOper));
        }
    }

    /**
     * 是否数字
     *
     * @param ch 数字参数
     * @return
     */
    private static boolean isDigit(char ch) {
        return ch >= '0' && ch <= '9';
    }

    /**
     * 是否操作符
     *
     * @param op 操作符
     * @return
     */
    private static boolean isOperator(char op){
        for(String ops : OPERATOR_PRIORITY ){
            if( ops.indexOf(op) != -1 ) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取操作符优先级
     *
     * @param op 操作符
     * @return
     */
    private static int getPriority(char op){
        for( int i = 0; i < OPERATOR_PRIORITY.length; ++i ){
            if( OPERATOR_PRIORITY[i].indexOf(op) != -1 ){
                return i;
            }
        }
        throw new RuntimeException( new Exception("don't support operator: " + op) );
    }
}

附上测试用例:

package com.sylar;

import org.junit.Assert;
import org.junit.Test;

public class ExpressBracketMatchTest {

    @Test
    public void bracketTest0() {
        String result = ExpressBracketMatch.match("1+2");
        Assert.assertEquals("(1+2)", result);
    }

    @Test
    public void bracketTest1() {
        String result = ExpressBracketMatch.match("1+3*4+5");
        Assert.assertEquals("((1+(3*4))+5)", result);
    }

    @Test
    public void bracketTest2() {
        String result = ExpressBracketMatch.match("((1+3)*2");
        Assert.assertEquals("((1+3)*2)", result);
    }

    @Test
    public void bracketTest3() {
        String result = ExpressBracketMatch.match("(((1+3)*2-3");
        Assert.assertEquals("(((1+3)*2)-3)", result);
    }

    @Test
    public void bracketTest4() {
        String result = ExpressBracketMatch.match("1/2/3+3");
        Assert.assertEquals("(((1/2)/3)+3)", result);
    }

    @Test
    public void bracketTest5() {
        String result = ExpressBracketMatch.match("1/2/3+3*4");
        Assert.assertEquals("(((1/2)/3)+(3*4))", result);
    }

    @Test
    public void bracketTest6() {
        String result = ExpressBracketMatch.match("1/(2/3)+3*5");
        Assert.assertEquals("((1/(2/3))+(3*5))", result);
    }

    @Test
    public void bracketTest7() {
        String result = ExpressBracketMatch.match("1/(2/3)+3*5^3");
        Assert.assertEquals("((1/(2/3))+(3*(5^3)))", result);
    }

    @Test
    public void bracketTest8() {
        String result = ExpressBracketMatch.match("1+2)*3-4)*5-6)))");
        Assert.assertEquals("(((((1+2)*3)-4)*5)-6)", result);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值