Sunteți pe pagina 1din 16

Lectia nr. 1. – Stiva. Evaluarea expresiilor.

Stiva
Stiva este un caz particular de lista care funcționează pe principiul LIFO (last in – first out,
ultimul intrat este primul servit, puteți sa va gândiți la o stiva de materiale pentru care un nou
material se va adăuga întotdeauna deasupra si se va extrage tot de deasupra). Prin urmare
principalele prelucrări care se refera la aceasta structura de date vor fi:

- creare stiva
- listare stiva (parcurgere in ordine inversa creării)
- adăugare la sfârșit ( peste vârful stivei, operație numita push ( ) )
- ștergere element din vârful stivei (operație numita pop( ) )
- prelucrarea vârfului stivei (operație numita top() )

Alocare statica

struct Stiva
{
int st[Nmax];
int top;

void Init(){
top = - 1;
}

int Empty(){
if(top == -1) return 1;
return 0;
}
int Full(){
if(top == Nmax-1) return 1;
return 0;
}
int Top(){
return st[top];
}
void Push(int x){
if(Full())
cout << "Stack overflow error";
else
{
top++;
st[top] = x;
}
}
void Pop(){
if(!Empty())
top--;
}
};

Alocare dinamica
struct nod
Lectia nr. 1. – Stiva. Evaluarea expresiilor.

{
int info;
nod *urm;V
};

nod *vf;

void Push(nod *&vf, int x)


{
nod *c=new nod;
c->info=x;
c->urm=vf;
vf=c;
}

void Pop(nod *&vf)


{
nod *c=vf;
vf=vf->urm;
delete c;
}

int Top(nod *vf)


{
return vf->info;
}

int Empty(nod *vf)


{
return vf==0;
}

Stiva in STL
Se foloseste <stack>
stack<int> st;
st.push(x); -adăugare nod in vârf
st.empty(); -verificare daca e vida
st.pop(); -ștergere nod din vârf
st.top(); -accesare element din vârf
st.size(); -dimensiune stiva

Exemplu de problema rezolvata cu stiva in STL


#include <bits/stdc++.h>
using namespace std;
int main()
{
Lectia nr. 1. – Stiva. Evaluarea expresiilor.

stack<int>st;
int n,x;
char s[5];
cin>>n;
cin.get();
for(;n;n--)
{
cin>>s;
if(strcmp(s,"push")==0)
{
cin>>x;
cin.get();
st.push(x);
}
else if(strcmp(s,"pop")==0)
{
if(!st.empty()) st.pop();
}
else if(!st.empty()) cout<<st.top()<<"\n";
}
return 0;
}

Forma poloneza postfixata.

Problema: Se da o expresie aritmetica in forma normala. Sa se afișeze


expresia in forma poloneza postfixata.

Observații:
• se tine cont de ordinea efectuării operațiilor, vor fi setate priorități
• pentru operatorii care nu pot fi folosiți la un moment dat (datorita ordinii
efectuării operațiilor), se va folosi stiva

Input (a *(b - c) + d /(e + f *h) -i)


Output abc-*defh* + /i- +
Rezolvare
1. Se definesc prioritățile operatorilor
‘(‘,’)’ – prioritate 0
‘*‘,’/’ – prioritate 1
‘+‘,’-’ – prioritate 2
2. Expresia matematica se citește caracter cu caracter si este de forma (E)
3. Operanzii se introduc in vectorul fp
Lectia nr. 1. – Stiva. Evaluarea expresiilor.

4. Operatorii se introduc in stiva st, apoi se transfera in fp cu excepția ‘(‘,’)’


5. In funcție de valoarea si prioritatea operatorului din vârful stivei se fac
următoarele operații:
✓ daca (prioritate(op)==1), nu se face nici o operație suplimentara
✓ daca (prioritate(op)==2), se scoate temporar operatorul op din vârful
stivei, se transfera din stiva in fp toți operatorii cu prioritate 1, apoi se
reintroduce in stiva operatorul op
✓ daca (op==‘)’), se scot din stiva toți operatorii pana când (op==‘(’) si se
adaugă in fp. Cu siguranța in acest moment, operatorii dintre paranteze
vor avea aceeași prioritate!
✓ La final se scot operatorii rămași din stiva si se adaugă in fp
Solutie:
#include<iostream>
#include<stack>
#include<string>
using namespace std;

string InfixToPostfix(string expresie);


int MaiMare(char op1, char op2);
bool Termen(char C);
bool Semn(char C);

int main() {
string expresie;
getline(cin,expresie);
string polon=InfixToPostfix(expresie);
cout<<polon;
return 0;
}

string InfixToPostfix(string expresie) {


stack<char> S;
string postfix = "";
for(int i = 0; i< expresie.length(); i++) {
if(expresie[i] == ' ') continue;
else if(Semn(expresie[i])) {
Lectia nr. 1. – Stiva. Evaluarea expresiilor.

while(!S.empty() && S.top() != '(' &&


MaiMare(S.top(),expresie[i])) {
postfix+= S.top();
S.pop();
}
S.push(expresie[i]);
} else if(Termen(expresie[i])) {
postfix +=expresie[i];
} else if (expresie[i] == '(') {
S.push(expresie[i]);
} else if(expresie[i] == ')') {
while(!S.empty() && S.top() != '(') {
postfix += S.top();
S.pop();
}
S.pop();
}
}
while(!S.empty()) {
postfix += S.top();
S.pop();
}
return postfix;
}

bool Termen(char C) {
if(C >= '0' && C <= '9' || C >= 'a' && C <= 'z' || C >=
'A' && C <= 'Z') return true;
return false;
}

bool Semn(char C) {
if(C == '+' || C == '-' || C == '*' || C == '/' )return
true;
return false;
}
Lectia nr. 1. – Stiva. Evaluarea expresiilor.

int Precedenta(char op) {


int pre = -1;
switch(op) {
case '+':
case '-':
pre = 1;
break;
case '*':
case '/':
pre = 2;
break;
}
return pre;
}
int MaiMare(char op1, char op2) {
int op1pre = Precedenta(op1);
int op2pre = Precedenta(op2);
return op1pre >= op2pre ? true: false;
}

Problema: Se da o expresie aritmetica in forma normala si valorile fiecărui


operand al expresiei. Sa se calculeze rezultatul expresiei aritmetice.

Algoritmul de evaluare a unei expresii in format postfixat:


Se parcurge expresia de la stânga la dreapta
1. daca este întâlnit un operand (variabila/număr/etc..), acesta este pus in stiva;
2. daca este întâlnit un operator (operație aritmetica), atunci se scot ultimele
doua elemente din stiva si este aplicat operatorul asupra lor; rezultatul operației
este pus in stiva.
Când s-a terminat de parcurs expresia inițială, rezultatul final se găsește in stiva.
Solutie
#include<iostream>
#include<stack>
#include<string>

using namespace std;


Lectia nr. 1. – Stiva. Evaluarea expresiilor.

int EvaluatePostfix(string expresie);


int PerformOperation(char operation, int operand1, int
operand2);
bool IsOperator(char C);
bool IsNumericDigit(char C);

int main()
{
string expresie;
getline(cin,expresie);
int result = EvaluatePostfix(expresie);
cout<<result<<"\n";
}

int EvaluatePostfix(string expresie)


{

stack<int> S;

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

if(expresie[i] == ' ') continue;

else if(IsOperator(expresie[i])) {

int operand2 = S.top(); S.pop();


int operand1 = S.top(); S.pop();
int result = PerformOperation(expresie[i], operand1,
operand2);
S.push(result);
}
else if(IsNumericDigit(expresie[i])){
int operand = 0;
while(i<expresie.length() &&
IsNumericDigit(expresie[i])) {
operand = (operand*10) + (expresie[i] - '0');
Lectia nr. 1. – Stiva. Evaluarea expresiilor.

i++;
}
i--;
S.push(operand);
}
}

return S.top();
}

bool IsNumericDigit(char C)
{
if(C >= '0' && C <= '9') return true;
return false;
}

bool IsOperator(char C)
{
if(C == '+' || C == '-' || C == '*' || C == '/')
return true;

return false;
}

int PerformOperation(char operation, int operand1, int


operand2)
{
if(operation == '+') return operand1 +operand2;
else if(operation == '-') return operand1 - operand2;
else if(operation == '*') return operand1 * operand2;
else if(operation == '/') return operand1 / operand2;

else cout<<"Eroare\n";
return -1;
}
Lectia nr. 1. – Stiva. Evaluarea expresiilor.

Problema Evaluarea unei expresii infoarena


Soluție:
#include<fstream>
#define N 100000
using namespace std;
ifstream fin("evaluare.in");
ofstream fout("evaluare.out");

char c,semn[N], st[N];


int i,n,k,nr,gasitnr,fp[N];
long long steval[100];

int main()
{

while(fin>>c)
{
if(c>='0'&&c<='9')
{
gasitnr=1;
nr=nr*10+(c-'0');
}
else
{
if(gasitnr)
{
fp[++n]=nr;
nr=0;
gasitnr=0;
}

if(c=='(' ||c=='+'||c=='-'||c=='*'||c=='/')
{
st[++k]=c;
if(st[k]=='+'||st[k]=='-')
Lectia nr. 1. – Stiva. Evaluarea expresiilor.

{
while(st[k-1]=='+'||st[k-1]=='-'|| st[k-1]=='*'||
st[k-1]=='/')
{
semn[++n]=st[k-1];
st[k-1]=st[k];
k--;
}
}
else
if(st[k]=='*'||st[k]=='/')
{

while(st[k-1]=='*'||st[k-1]=='/')
{
semn[++n]=st[k-1];
st[k-1]=st[k];
k--;
}
}
}
else
if(c==')')
{
while(st[k]!='(')
{
semn[++n]=st[k];
k--;
}
k--;
}
}
}

if(gasitnr)
{
fp[++n]=nr;
Lectia nr. 1. – Stiva. Evaluarea expresiilor.

nr=0;
gasitnr=0;
}

while(k)
{
semn[++n]=st[k];
k--;
}

k=0;
for(i=1;i<=n;++i)
{
if(semn[i]!='+'&&semn[i]!='-'&&semn[i]!='*'&&semn[i]!='/')
steval[++k]=fp[i];
else
{
switch(semn[i])
{
case '+':steval[k-1]=steval[k-1]+steval[k]; break;
case '-':steval[k-1]=steval[k-1]-steval[k]; break;
case '*':steval[k-1]=steval[k-1]*steval[k]; break;
case '/':steval[k-1]=steval[k-1]/steval[k]; break;
}
k--;
}
}
fout<<steval[1];
return 0;
}

O alta varianta :
In aplicația care urmează, structura de stocare expresiei matematice in scriere
postfixata este coada.
#include <bits/stdc++.h>
using namespace std;
Lectia nr. 1. – Stiva. Evaluarea expresiilor.

struct NodStiva{
char opr;
NodStiva* next;
};
struct NodCoada{
int opd;
char opr;
NodCoada* next;
};
NodStiva* push(NodStiva* vf,char c){
NodStiva* nou=new NodStiva;
nou->opr=c;
nou->next=vf;
return nou;
}

NodStiva* pop(NodStiva* vf,char *c){


if(vf){
*c=vf->opr;
NodStiva* t=vf;
vf=vf->next;
delete t;
return vf;
}
return vf;
}

NodCoada* put(NodCoada* c,int v,char o){


NodCoada* nou=new NodCoada;
nou->opd=v;
nou->opr=o;
nou->next=NULL;
if(!c)
return nou;
else{
NodCoada* t=c;
Lectia nr. 1. – Stiva. Evaluarea expresiilor.

while(t->next)
t=t->next;
t->next=nou;
return c;
}
}

int prioritate(char c){


switch(c){
case '(': return 1;
case ')': return 2;
case '+':
case '-': return 3;
case '*':
case '/': return 4;
default: return 5;
}
}

int main(){
NodStiva* stack=NULL;
NodCoada* queue=NULL;
char ExprInfix[100], SubExpr[100], o;
int vb, vb_op=0;

cout<<"Introduceti expresia matematica in forma infixata: ";


cin>>ExprInfix;

//algoritmul de transformare infixata -> postfixata cu


operanzi \ intregi fara semn
int i=0;

//extragere token operand/operator


while(ExprInfix[i]!='\0'){
int k=0;
if(ExprInfix[i]>47 && ExprInfix[i]<58){
while(ExprInfix[i]>47 && ExprInfix[i]<58){
Lectia nr. 1. – Stiva. Evaluarea expresiilor.

SubExpr[k]=ExprInfix[i];
k++;
i++;
}
SubExpr[k]='\0';
vb=1;
}
else{
SubExpr[k]=ExprInfix[i];
SubExpr[k+1]='\0';
i++;
vb=0;
}

if(vb){
o=0;
queue=put(queue,atoi(SubExpr),o);
}
else{
if(SubExpr[0]=='('){
stack=push(stack,SubExpr[0]);
}
else{
if(SubExpr[0]==')'){
stack=pop(stack,&o);
while(o!='('){
queue=put(queue,0,o);
stack=pop(stack,&o);
}
}
else{
if(prioritate(SubExpr[0])<5){
if(stack){
while(stack && prioritate(stack-
>opr)>prioritate(SubExpr[0])){
stack=pop(stack,&o);
queue=put(queue,0,o);
Lectia nr. 1. – Stiva. Evaluarea expresiilor.

}
}

stack=push(stack,SubExpr[0]);
}
else{
cout<<"Operator incorect \
introdus!";
vb_op=1;
}
}
}
}
}

while(stack){
stack=pop(stack,&o);
queue=put(queue,0,o);
}

//afisarea expresiei in scriere postfixata


NodCoada* t;
if(!vb_op){
t=queue;
while(t){
if(t->opd)
cout<<t->opd<<" ";
else
cout<<t->opr<<" ";
t=t->next;
}
}

//dezalocare memorie heap alocata pentru structura coada


while(queue){
t=queue;
queue=queue->next;
Lectia nr. 1. – Stiva. Evaluarea expresiilor.

delete t;
}
}

Restrictiile de operatiei de conversie implementata in aplicatia de mai sus vizeaza:

• Toti operanzii sunt intregi pozitivi si nenuli;


• Sunt utilizate doar paranteze rotunde pentru fortarea prioritatii de evaluare a unor
subexpresii.

Tema infoarena: Bool, Expresii min-max, Apel, Logic, Dir, Rsp

Tema pbinfo: 2185,2228

S-ar putea să vă placă și