Инфикс в постфикс

Я пытаюсь преобразовать инфикс в постфикс. Например: «20 + 2 * 3 + (2 * 8 + 5) * 4» -> 20 2 3 * + 2 8 * 5 + 4 * + вот мой код:

Stack<Character> s = new Stack<Character>();
String postfix = "";
boolean enter = true;
String infixExpr = "20 + 2 * 3     + (2*8 + 5)* 4";

for(int i = 0;i<infixExpr.length();i++){

    if(Character.isDigit(infixExpr.charAt(i)) == true){
        postfix = postfix + infixExpr.charAt(i);
    }
    if(infixExpr.charAt(i) == '+' || infixExpr.charAt(i) == '-'){
        if(s.isEmpty() == true){
            s.push(infixExpr.charAt(i));
        }
        else{
            if(s.peek() == '*' || s.peek() == '/' || s.peek() == '+' || s.peek() == '-'){
                while(s.isEmpty()== false){
                    postfix = postfix + s.pop();
                }
                s.push(infixExpr.charAt(i));
            }
            else{
                s.push(infixExpr.charAt(i));
            }
        }
    }
    if(infixExpr.charAt(i) == '*' || infixExpr.charAt(i) == '/' ){
        if(s.isEmpty() == true){
            s.push(infixExpr.charAt(i));
        }
        else{
            if(s.peek()== '+' || s.peek() == '-' || s.peek() == '('){
                s.push(infixExpr.charAt(i));
            }
            else if(s.peek() == '*' || s.peek() == '/'){
                while(s.isEmpty()== false){
                    postfix = postfix + s.pop();
                }
                s.push(infixExpr.charAt(i));
            }
        }
        if(infixExpr.charAt(i) == '('){
            s.push(infixExpr.charAt(i));
        }
        if(infixExpr.charAt(i) == ')'){
            while(enter){

                if(s.peek() == '('){
                    enter = false;
                }
                else{
                    postfix = postfix + s.pop();
                }
            }
        }
    }
}

Как написано вверху, я предполагаю получить «20 2 3 * + 2 8 * 5 + 4 * +», но я получаю «2023 * + 28 * + 54», что неверно, и я много раз пересматривал код и до сих пор Я не вижу проблемы. Было бы здорово, если бы кто-нибудь мог помочь.


person CodingAround    schedule 16.12.2014    source источник
comment
en.wikipedia.org/wiki/Shunting-yard_algorithm   -  person Alexis King    schedule 16.12.2014
comment
Вы пытались пройти через это с помощью отладчика?   -  person Dawood ibn Kareem    schedule 16.12.2014


Ответы (3)


Пространства

Вы не ставите пробелы в свою постфиксную переменную. Вы только проверяете, является ли текущий символ одним из «интересных» символов (цифры, операторы), но не пробелом. В результате, если текущий символ является пробелом, вы просто пропускаете его и не копируете в постфикс.

Поскольку единственное, что вы вставляете в постфикс, — это проверенные вами символы, в итоге у вас вообще не будет пробелов.

Вы можете решить это следующим образом:

  • Добавьте логическое значение с именем inNumber, сначала установите для него значение true.
  • Всякий раз, когда вы обрабатываете цифру, прежде чем добавлять ее к postfix, проверьте, верно ли inNumber. Если это так, сначала добавьте пробел.
  • Если вы только что обработали цифру, установите inNumber в значение true.
  • Если вы обрабатываете оператор, установите для inNumber значение false.
  • Всякий раз, когда вы добавляете какой-либо оператор в стек, сначала добавьте пробел.

Идея этого inNumber заключается в том, что цифры, принадлежащие одному и тому же числу, не должны иметь пробелов между ними. Но если цифра добавляется к postfix после того, как мы обработали оператор в предыдущем раунде, то она принадлежит новому числу, поэтому там должен быть пробел.

Таким образом, ваш код обработки цифр должен выглядеть так:

        if(Character.isDigit(infixExpr.charAt(i)) == true){
            if ( ! inNumber ) {
                postfix += " ";
            }
            postfix = postfix + infixExpr.charAt(i);
            inNumber = true;
        }

И в каждом if, указывающем на оператора, должно быть inNumber = false.

И каждое место, где вы добавляете оператор к постфиксу, должно выглядеть так:

        postfix = postfix + " " + s.pop();

Обработка скобок

Другая ваша проблема связана с обработкой ().

Во-первых, вы помещаете код, который проверяет ( и ) внутри if для * и /. Конечно, если символ в позиции i равен * или /, это не ( и не ), поэтому этот код никогда не вызывается.

Таким образом, вы должны переместить if для скобок наружу, на тот же уровень, что и if для чисел и операторов.

Кроме того, вы неправильно используете enter. Если у вас есть скобки внутри скобок, например ( 3 + ( 5 + 7 ) ), то при первом ) вы вернетесь к скобкам после 5, что нормально. Но тогда enter станет ложным и вы не будете корректно обрабатывать внешнюю пару. Это также верно для (3 + 5 ) * ( 7 + 2 ), потому что вы не устанавливаете enter в true снова после начала программы.

Вместо использования enter вы должны извлечь то, что находится в стеке, и проверить, было ли это (:

        if(infixExpr.charAt(i) == '('){
            inNumber = false;
            s.push(infixExpr.charAt(i));
        }
        if(infixExpr.charAt(i) == ')'){
            inNumber = false;
            char popped;
            while ( ( popped = s.pop() ) != '(' ) {
                    postfix = postfix + " " + popped;
            }
        }        

Неизвлекаемые операторы

Наконец, вы закончите, когда закончите сканирование ввода. Но в этот момент у вас все еще будут операторы, ожидающие в стеке! Вы должны вытолкнуть их все и добавить к postfix. Итак, после цикла у вас должно быть:

    while ( ! s.isEmpty()) {
        postfix += " " + s.pop();
    }

Дополнительные замечания:

  • Было бы лучше и понятнее, если бы вместо всех этих операторов if вы использовали оператор switch.
  • Нет смысла сравнивать логическое выражение с true. Правильный способ написать if (s.isEmpty() == true) — просто if (s.isEmpty()), а вместо s.isEmpty() != true использовать ! s.isEmpty().
  • Вы не выполняете проверку синтаксиса. Я не уверен, что это потому, что это домашнее задание, но в реальной жизни вы должны проверить, что каждому ( соответствует ), что каждый оператор имеет два операнда, а также обрабатывать отрицательные числа, которые могут иметь - в начале.
person RealSkeptic    schedule 16.12.2014

Проблема в том, что вы не добавляете пробелы. Однако вы не можете просто добавить пробел между каждым числом. Вы должны убедиться, что пробелы не добавляются между цифрами целого числа. Чтобы решить эту проблему, я просто добавил postfix += " "; после if(infixExpr.charAt(i) == '+' || infixExpr.charAt(i) == '-') и еще раз после if(infixExpr.charAt(i) == '*' || infixExpr.charAt(i) == '/' ). Логика этого заключается в том, что, столкнувшись с оператором, вы знаете, что все, что было до оператора, было числом. Теперь, когда я запускаю программу, вывод 20 2 3 *+2 8 *+5 4. Есть еще несколько пробелов, которые нужно добавить между операторами, но я позволю вам справиться с этим.

Модифицированный код:

    if(infixExpr.charAt(i) == '+' || infixExpr.charAt(i) == '-'){
        postfix += " ";

...

    if(infixExpr.charAt(i) == '*' || infixExpr.charAt(i) == '/' ){
        postfix += " ";
person nLee    schedule 16.12.2014

вот мой код для вашего ответа

#include<stack>
#include<iostream>
using namespace std;
bool high(char a,char b)
{
  if(b==' ')
    return true;
  else if(a==b)
    return false;
  else if(a=='/')
    return true;
  else if(a=='*'&&b!='/')
    return true;
  else if(b=='/')
    return false;
  else if(a!='/'&&b=='*')
    return false;
  else if(b=='-')
    return true;
  else if(a=='-'&&b!='(')
    return false;
  else if(b=='(')
    return true;
  else if(a=='(')
    return true;
  else if(a==')')
    return false;
}
main()
{
int k=0;
string s;
stack<char>s1;
s1.push(' ');
char ch;
while(cin>>ch)
{
    if(ch=='(')
    {
    k=1;
    s1.push(ch);}
    else if(ch>47&&ch<58)
    s.push_back(ch);
    else if(high(ch,s1.top()))
    s1.push(ch);
    else if(!high(ch,s1.top())&&ch!=')')
    {
        while(!s1.empty()&&!high(ch,s1.top()))
        {
            s.push_back(s1.top());
            s1.pop();
        }   
    s1.push(ch);}
    else if(ch==')')
    {
        while(!s1.empty()&&s1.top()!='(')
        {
            s.push_back(s1.top());
            s1.pop();
        }
        s1.pop();
        k=0;
    }

}
while(!s1.empty())
{
    s.push_back(s1.top());s1.pop();
}
cout<<s;
}
person bhavneet singh    schedule 08.01.2017
comment
Добавьте некоторое объяснение с ответом о том, как этот ответ помогает ОП в устранении текущей проблемы. - person ρяσѕρєя K; 08.01.2017
comment
Если это не решит его проблему, это не ответ, а если решит, вам нужно указать, почему. - person user207421; 08.01.2017