Search code examples
javascriptpythonpostfix-notationinfix-notationrpn

Converting postfix (reverse polish notation) expressions to infix with minimal parentheses


I am looking for an algorithm to convert a postfix expressions to infix expressions but with minimal parentheses.

I am asking it here after searching Google Stack Overflow. I only found a single answer to my question but it was in Java and I don't understand that language. I am looking for a algorithm but if you can give a JavaScript or Python (the only languages I understand) implementation I will be very thankful to you.

This is what I have been able to do on the base of my current understanding.

const postfixToInfix = RPN => {
  let convert = RPN.replace(/\^/g,'**').split(/\s+/g).filter(el => !/\s+/.test(el) && el !== '')
  let stack = []
  let result = []
  let friends = {"+" : ["+","-","*","/"],"-":[],"/":["*"],"*":["/","*"],"**":["+","-","*","/"]}
  convert.forEach(symbol => {
    if(!isNaN(parseFloat(symbol)) && isFinite(symbol)){
      result.push(symbol)
    }
    else if (Object.keys(friends).includes(symbol)) {
      a = result.pop()
      b = result.pop()
      if(stack.length !==0){
          if(friends[symbol].includes(stack.pop())){
            result.push(`${b} ${symbol} ${a}`)
            stack.push(symbol)
          }
          else{
            result.push(`(${b}) ${symbol} ${a}`)
            stack.push(symbol)
          }
      }
      else {result.push(`${b} ${symbol} ${a}`);stack.push(symbol)}
    }
    else throw `${symbol} is not a recognized symbol`
  })
  if(result.length === 1) return result.pop()
  else throw `${RPN} is not a correct RPN`
}

But this code is giving unexpected results.


Solution

  • Ok I fixed the problem myself. Thought I shall write the answer for future use and other users. The answer is based on the algorithm in this SO answer.

    const postfixToInfix = RPN => {
      let convert = RPN.replace(/\^/g,'**').split(/\s+/g).filter(el => !/\s+/.test(el) && el !== '')
      let stack = []
      let result = []
      let precedence = {null : 4 ,'**':3 ,'/' : 2,'*': 2,'+':1,'-':1 }
      convert.forEach(symbol => {
        let stra,strb
        if(!isNaN(parseFloat(symbol)) && isFinite(symbol)){
          result.push(symbol)
          stack.push(null)
        }
        else if (Object.keys(precedence).includes(symbol)) {
          let [a,b,opa,opb] = [result.pop(),result.pop(),stack.pop(),stack.pop()]
          if(precedence[opb] < precedence[symbol]) {
             strb = `(${b})`
          }
          else{
             strb = `${b}`
          }
          if((precedence[opa] < precedence[symbol]) || ((precedence[opa] === precedence[symbol]) && ["/","-"].includes(symbol) )){
             stra = `(${a})`
          }
          else {
             stra = `${a}`
          }
          result.push(strb +symbol + stra)
          stack.push(symbol)
      }
        else throw `${symbol} is not a recognized symbol`
      })
      if(result.length === 1) return result.pop()
      else throw `${RPN} is not a correct RPN`
    }
    console.log(postfixToInfix('1 2 3 - + 4 5 - 6 7 - 8 + / * ')) //(1+2-3)*(4-5)/(6-7+8)