Problem z implementacją ONP

0

Witam. Mam problem z implementacją tego zadania:

Oblicz wartość wyrażenia zapisanego w postaci ONP. Działania to: - (odejmowanie), + (dodawanie), / (dzielenie całkowite), * (mnożenie). Wszystkie liczby są jednocyfrowe.
Postać ONP (czyli Odwrotna notacja polska) to zapis działań arytmetycznych, w którym argumenty wyrażenia poprzedzają to wyrażenie. Na przykład zamiast
2 + 3
pisze się
2 3 +
natomiast zamiast
(2 + 3) * 6
będzie
2 3 + 6 *
Wejście

W pierwszym wierszu dana jest jedna liczba (<=1000), mówiąca ile będzie zestawów danych. Każdy zestwa składa się w dwóch wierszy. W pierwszym dana jesli długość wyrażenia (<=1000). W drugim wierszu podane jest wyrażenie. Występują w nim tylko znaki: 0,1,2,3,4,5,6,7,8,9,-,+,/,*. Wszystkie liczby w wyrażeniu należy traktować jako liczby jednocyfrowe. Możesz założyć, że wynik zmieści się zakresie int'a
Wyjście

Dla każdego zestawu danych należy wypisać jedną liczbę całkowitą będącą wynikiem wyrażenia, lub wypisać słowo BRAK gdy wynik ten nie istnieje, tj. np. wyrażenie jest niepoprawne, lub np. występuje w nim dzielenie przez 0.
Przykład

Dla danych wejściowych
3
7
62-01+/
9
12345****
11
12--345****
poprawną odpowiedzią jest
4
120
BRAK

Mianowicie nie widzę żadnego błędu w moim programie. Sprawdzarka wyrzuca mi błąd, że jest nieprawidłowy wynik. Mógłby ktoś nakierować na błąd w moim programie, lub wskazać przykład dla którego wynik jest niepoprawny? Niżej zamieszczam sam program:

#include <iostream>
#include <string>
#include <stack>
#include <cstdlib>
#include <vector>

using namespace std;

int main()
{
    int ile_razy, dlugosc_wyrazenia, z, i;
    stack<int> stos;
    string wyrazenie, tymczasowy;
    int zmienna1, zmienna2, ile_liczb=0, ile_znakow=0;
    bool dobrze=true;
    cin>>ile_razy;
    vector<int> w;
    bool tablicaboolow[ile_razy];
    for(i=1; i<=ile_razy; i++)
    {
        cin>>dlugosc_wyrazenia>>wyrazenie;
        if(dlugosc_wyrazenia!=wyrazenie.size())
             dobrze=false;
        for(int k=0;k<dlugosc_wyrazenia; k++)
        {
            if(wyrazenie[k]>=48 && wyrazenie[k]<=57)
            {
                tymczasowy=wyrazenie[k];
                int h=atoi(tymczasowy.c_str());
                stos.push(h);
                ile_liczb++;
            }
            if(wyrazenie[k]==43 || wyrazenie[k]==42 || wyrazenie[k]==45 || wyrazenie[k]==47)
            {
                if(stos.size()>=2)
                {
                zmienna2=stos.top();
                stos.pop();
                zmienna1=stos.top();
                stos.pop();
                if(wyrazenie[k]==43)
                    z=zmienna1+zmienna2;
                if(wyrazenie[k]==42)
                    z=zmienna1*zmienna2;
                if(wyrazenie[k]==45)
                    z=zmienna1-zmienna2;
                if(wyrazenie[k]==47)
                {
                    if(zmienna2==0)
                       dobrze=false;
                       else
                           z=zmienna1/zmienna2;
                }
                stos.push(z);
                }
                ile_znakow++;
            }
          if(k==dlugosc_wyrazenia-1)
          {
              if(stos.size()!=1)
                   dobrze=false;
          }
          if(ile_znakow>=ile_liczb)
               dobrze=false;
        }
        if(dobrze==true)
              {
                  w.push_back(stos.top());
                  tablicaboolow[i-1]=true;
              }
        else
              tablicaboolow[i-1]=false;
        while(!stos.empty())
        stos.pop();
        dobrze=true;
        wyrazenie="";
        ile_liczb=0;
        ile_znakow=0;
    }
    for(int l=0; l<ile_razy; l++)
    {
        if(tablicaboolow[l]==false)
        cout<<"BRAK"<<endl;
        else
        cout<<w[l]<<endl;
    }
    return 0;
}
0

Za wiele nie zmieniłem. Miałem problem z przeniesieniem wypluwacza wyniku na funkcję:

'''cpp
#include <iostream>
#include <string>
#include <stack>
#include <cstdlib>
#include <vector>

using namespace std;

void dzialanie(string &wyrazenie, stack<int> &stos, int dlugosc_wyrazenia, bool &dobrze)
{
string tymczasowy;
int ile_liczb=0;
int ile_znakow=0;
int zmienna1,zmienna2, z;
for(int k=0;k<dlugosc_wyrazenia; k++)
{
if(wyrazenie[k]>=48 && wyrazenie[k]<=57)
{
tymczasowy=wyrazenie[k];
int h=atoi(tymczasowy.c_str());
stos.push(h);
ile_liczb++;
}
if(wyrazenie[k]==43 || wyrazenie[k]==42 || wyrazenie[k]==45 || wyrazenie[k]==47)
{
if(stos.size()>=2)
{
zmienna2=stos.top();
stos.pop();
zmienna1=stos.top();
stos.pop();
if(wyrazenie[k]==43)
z=zmienna1+zmienna2;
if(wyrazenie[k]==42)
z=zmienna1*zmienna2;
if(wyrazenie[k]==45)
z=zmienna1-zmienna2;
if(wyrazenie[k]==47)
{
if(zmienna2==0)
dobrze=false;
else
z=zmienna1/zmienna2;
}
stos.push(z);
}
ile_znakow++;
}
if(k==dlugosc_wyrazenia-1)
{
if(stos.size()!=1)
dobrze=false;
}
if(ile_znakow>=ile_liczb)
dobrze=false;
}

}

int main()
{
int ile_razy, dlugosc_wyrazenia;
stack<int> stos;
string wyrazenie;
bool dobrze=true;
cin>>ile_razy;
vector<int> w;
bool tablicaboolow[ile_razy];
for(int i=1; i<=ile_razy; i++)
{
cin>>dlugosc_wyrazenia>>wyrazenie;
if(dlugosc_wyrazenia!=wyrazenie.size())
dobrze=false;
dzialanie(wyrazenie, stos, dlugosc_wyrazenia, dobrze);
if(dobrze==true)
{
w.push_back(stos.top());
tablicaboolow[i-1]=true;
}
else
tablicaboolow[i-1]=false;
while(!stos.empty())
stos.pop();
dobrze=true;
wyrazenie="";
}
for(int l=0; l<ile_razy; l++)
{
if(tablicaboolow[l]==false)
cout<<"BRAK"<<endl;
else
cout<<w[l]<<endl;
}
return 0;
}
'''

0

Sama logikę funkcji eval mogę Ci wydzielić w pseudokodzie, IO i przygotowanie wejścia do funkcji Musisz zrobić sam, dla mnie w C++ to byłaby męczania:) wiem, że string.split() nie ma w std::, jest w boost czy jakoś tak. Funkcja działa, przy założeniu, że dostaje na wejściu taki, na przykład, string:
"7 8 + 3 2 + /"
Czyli wszystko oddzielone spacjami
Potem w ciele funkcji, używając split(" "), zmienia to na listę (vector):
['7', '8', '+', '3', '2', '+', '/']
Oczywiście wszystko to Możesz łatwo zmodyfikować do bardziej ogólnego wejścia
Potrzebne jest jeszcze pomocnicze dom_math(operand, op1, op2) do wykonywania obliczeń

Algorytm iteruje po tej liście, funkcje do_math i eval_onp:

fun do_math(op, op1, op2):  # przyjmuje string i dwa integery, zwraca integera
    if op == "*":
        return op1 * op2;
    elif op == "/":
        return op1 / op2;
    elif op == "+":
        return op1 + op2;
    else:
        return op1 - op2;


fun eval_onp(input_str):  # na wejściu string, zwraca integera/floata - zależy jak dzieli '/'
    op_stack = stack();  ## Utworzenie stosu
    input_list = input_str.split(" ");  # split inputu do listy
    for token in input_list:
        if token in "0123456789":  # jeśli liczba (działa tylko dla jednocyfrowych)
            op_stack.push(int(token))  # wrzuć  skonwertowaną do integera liczbę na  stos 
        else:  # a jak nie, to token to operator
            op1 = op_stack.pop(); #  pop dwa razy (bo działania dwuargumentowe)
            op2 = op_stack.pop(); # jak mamy operator to na stosie musza być dwie cyfry
            val = do_math(token, op2, op1);  # oblicz, wysyłając token jako operator
            op_stack.append(val); # wrzuć wynik na stos
    return op_stack.pop();  # Na końcu powinna być tylko jedna liczba na stosie: wynik całego działania,
                            # więc ja zwracamy


print(eval_onp('7 8 + 3 2 + /')) # -> 3.0 W C++ '/' dzieli w integerach, ale generalnie chyba wynik jest floatem
print(eval_onp('6 2 - 0 1 + /')) # -> 4.0
0

Kolego, to jest nieczytelne. Proponuję najpierw poprawić czytelność kodu zanim wrzucisz posta forum - usunąć magiczne liczby ('+' jest czytelniejszy niż 43 ...), rozdzielić na mniejsze funkcje, nazywać zmienne w sposób opisujący ich przeznaczenie, dodać komentarze.

lion137 dał Ci elegancki pseudokod, spróbuj to zaimplementować.

1 użytkowników online, w tym zalogowanych: 0, gości: 1