Sunteți pe pagina 1din 6

Evaluarea expresiilor

Se da un sir de caractere ce reprezinta o expresie aritmetica. Afisati rezultatul obtinut prin evaluarea
expresiei. Fisierul de intrare evaluare.in va contine pe prima linie un sir de caractere compus din
cifre ( '0' - '9' ), operatorii '+', '-', '*', '/' si paranteze( '(', ')' ).

Pentru evaluarea unei expresii vor fi prezentati 3 algoritmi.

1. Evaluarea folosind tehnica Divide et Impera

Ideea aici este de a gasi la fiecare pas ultima operatie care ar trebui executata. Ne aflam in urmatoarele
situatii

a. Exista cel putin un operator + sau – care nu se afla in nicio paranteza. In acest caz cel mai din
dreapta semn + - este ultima operatie care se executa
b. Exista cel putin un operator * sau / care nu se afla in nicio paranteza. Atunci, aceasta este
ultima operatie care se executa
c. Nu exista niciun semn in afara oricarei paranteze, deci expresie contine o pereche de paranteze
exterioare care pot fi eliminate
d. Expresia este formata dintr-un singur numar

Se vor trata pe rand cele 4 cazuri de mai sus, iar daca ne aflam in unul din primele doua, vom
determina pozitia semnului si vor calcula folosind divide et impera cele doua expresii operanzi
pentru semnul considerat, dupa care vom aplica operatia curenta pe rezultatele obtinute.

#include <iostream>
#include <fstream>
#include <string.h>

using namespace std;

char s[100005];

int cautas(int st, int dr, char s1, char s2)


{
int nr=0;
for(int i=dr;i>=st;i--)
{
if(s[i]==')')
nr++;
if(s[i]=='(')
nr--;
if(nr==0 && (s1==s[i] || s2==s[i]))
return i;
}
return -1;
}

int num(int st, int dr)


{
int numar=0;
for(int i=st;i<=dr;i++)
numar=numar*10+(s[i]-'0');
return numar;
}

int solve(int st, int dr)


{
int poz=cautas(st,dr,'+','-');
if(poz!=-1)
{
int e1=solve(st,poz-1);
int e2=solve(poz+1,dr);
if(s[poz]=='+')
return e1+e2;
return e1-e2;
}
poz=cautas(st,dr,'*','/');
if(poz!=-1)
{
int e1=solve(st,poz-1);
int e2=solve(poz+1,dr);
if(s[poz]=='*')
return e1*e2;
return e1/e2;
}
if(s[st]=='(' && s[dr]==')')
return solve(st+1,dr-1);
return num(st,dr);
}

int main()
{
ifstream fin("evaluare.in");
ofstream fout("evaluare.out");
fin.getline(s,100005);
int n=strlen(s);
fout<<solve(0,n-1);
return 0;
}
2. Algoritmul Dijkstra cu stiva
Acest algoritm mentine doua stive, una in care se insereaza operatorii si una in care se insereaza
operanzii. Aici si parantezele vor fi considerate operatori. Expresia este parcursa linear si fiecare
termen intalnit este introdus in una din cele doua stive, astfel:
Daca intalnim operanzi ei vor fi introdusi in stiva de operanzi
In cazul operatorilor se aplica urmatoarele reguli:
• Un operator poate fi introdus in stiva doar daca in varful stivei se afla un operator cu
prioritate mai mica.
• Cea mai mare prioritate o are ( , apoi * si / ,iar cea mai mica prioritate o au + si –
• Atunci cand intalnim un operand cu prioritate mai mica decat varful stivei, eliminam din
stiva toti operanzii cu prioritate mai mare decat operatorul curent apoi il introducem pe
acesta in stiva. Fiecare operator eliminat este aplicat primilor doi operanzi din varful
stivei, si rezultatul este reintrodus in stiva
• La intalnirea unei ) se elimia din stiva toti operatorii pana la prima (, acestia aplicandu-se
operanzilor din cealalta stiva.

Avantajul acestui algoritm este complexitatea liniara. Putin modificat, astfel incat la eliminarea
operatorilor din stiva acestia sa fie pur si simplu intordusi in stiva de operanzi, se obtine forma poloneza
postfixata a expresiei aritmetice.
#include
<iostream>
#include <fstream>
#include <stack>
#include <cstring>

using namespace std;

char s[100005];
int p=0;

stack <char> op;


stack <int> nr;

int eval(int x, int y, char semn)


{
switch (semn)
{
case '+': return x+y;
case '-': return x-y;
case '*': return x*y;
case '/': return x/y;
}
}

int nextnum()
{
int numar=0;
while(s[p]>='0' && s[p]<='9')
numar=numar*10+(s[p++]-'0');
return numar;
}

int prioritate(char s1, char s2)


{
if(s1=='(')
return 1;
if((s1=='-' || s1=='+') && (s2=='*' || s2=='/'))
return 1;
return 0;
}

int main()
{
ifstream fin("evaluare.in");
ofstream fout("evaluare.out");
fin.getline(s,100005);
int n=strlen(s);
while(p<n)
{
switch (s[p])
{
case '(':{op.push(s[p++]);break;}
case')':{
while(op.top()!='(')
{
int v2=nr.top();
nr.pop();
int v1=nr.top();
nr.pop();
char semn=op.top();
op.pop();
nr.push(eval(v1,v2,semn));
}
op.pop();
p++;
break;
}
case'+':
case'-':
case'*':
case'/':{
if(op.empty() || prioritate(op.top(),s[p])==1)
{
op.push(s[p++]);
}
else
{
do{
int v2=nr.top();
nr.pop();
int v1=nr.top();
nr.pop();
char semn=op.top();
op.pop();
nr.push(eval(v1,v2,semn));
}while(!op.empty() &&
prioritate(op.top(),s[p])==0);
op.push(s[p++]);

}
break;
}
default :{
nr.push(nextnum());
}
}

}
while(!op.empty())
{
int v2=nr.top();
nr.pop();
int v1=nr.top();
nr.pop();
char semn=op.top();
op.pop();
nr.push(eval(v1,v2,semn));
}
fout<<nr.top();
return 0;
}

3. Recursivitate indirecta
Acesta tehnica presupune existenta mai multor functii recursive care sa se reapeleze intre ele.
#include <cstdio>
#include <cstring>
#include <cctype>
#define Lmax 100005

using namespace std;

FILE *fin=freopen("evaluare.in","r",stdin);
FILE *fout=freopen("evaluare.out","w",stdout);

char s[Lmax];
int i=0;

int num();
int mult();

int solve()
{
long t=mult();
while(s[i]=='+' || s[i]=='-')
{
if(s[i]=='+')
{
i++;
t+=mult();
}
else
{
i++;
t-=mult();
}
}
return t;
}

int mult()
{
long t=num();
while(s[i]=='*' || s[i]=='/')
{
if(s[i]=='*')
{
i++;
t*=num();
}
else
{
i++;
t/=num();
}
}
return t;
}

int num()
{
int t=0;
if(s[i]=='(')
{
i++;
t=solve();
i++;
}
else
while(isdigit(s[i]))
{
t=t*10+s[i++]-'0';
}
return t;
}
void citire()
{
fgets(s,Lmax,stdin);
}

int main()
{
citire();
printf("%d\n",solve());
return 0;
}

Expresia este aici impartita in numere, subexpresii care sunt factorii unui produs, si subexpresii
care sunt termenii unei sume. Expresia este mai intai descompusa in termini ai
sumelor(deoarece + - sunt ultimele operatii care se executa) . Apoi fiecare astfel de subexpresie
este descompusa in factori ai unor produse, iar fiecare factor la randul lui poate fi un numar sau
o paranteza. Daca este paranteza se reaplica algoritmul, iar daca este numar se returneaza.

Probleme propuse: infoarena : bool, expresiiMinMax, logic, apel


Campion : expresie1, expresie2,expeval