La valutazione delle espressioni X=a / b – c + d – e – a * c (esempio di espressione) Per scrivere un’ espressione esistono due notazioni Infix es: 5+3 Postfix es 53+ (notazione polacca) Valutare la seguente espressione è molto semplice: 6 / 2 –3 + 4 * 2 = (6 / 2) –3 + (4 * 2)= 3 –3 +8 = 8 Mentre valutare la seguente espressione risulta piu complicato: 6 2 3 – 4 2 * +
La valutazione delle espressioni Come faccio a valutare l’ espressione postfix? Prendiamo la seguente espressione 234*+ Leggo il primo valore dell’ espressione postfix “2”,poiché è un numero lo metto nello stack Leggo il secondo valore dell’ espressione postfix “3”,poiché è un numero lo metto nello stack Leggo il terzo valore dell’ espressione postfix “4”,poiché è un numero lo metto nello stack
La valutazione delle espressioni Leggo il quarto valore dell’ espressione postfix “*”,poiché è un operatore allora tolgo due elementi dallo stack, su di essi svolgo l’ operazione letta e salvo il risultato nello stack Leggo il quinto valore dell’ espressione postfix “+”,poiché è un operatore allora tolgo due elementi dallo stack, su di essi svolgo l’ operazione letta e salvo il risultato nello stack Poiché nell' espressione postfix non ci sono più elementi allora il valore contenuto nello stack è il risultato dell’ espressione.
La valutazione delle espressioni Vediamo l’ algoritmo passo – passo: Espressione | stack[0] stack[1] stack[2] 6 | 6 2 | 6 2 / | 6/2=3 3 | 3 3 - | 3-3=0 4 | 0 4 2 | 0 4 2 * | 0 4*2=8 + | 0+8=8
La valutazione delle espressioni Poiché noi usiamo la notazione infix dobbiamo trovare un metodo per passare dalla notazioni infix a quella postfix Prendiamo la seguente espressione: A / b – c +d * e – a * c Partendo dall’ espressione infix, ne costruiamo un’altra mettendo le parentesi tonde per ogni operazione ((((a / b) – c ) + (d * e)) – ( a * c))
La valutazione delle espressioni A questo punto scorro con un ciclo l’ espressione e al posto della parentesi tonda chiusa metto l’ ultimo operatore letto. ( ( ( ( a / b) – c ) + (d * e) ) – ( a * c) ) ( ( ( ( a b / c –(d e * + ( a c * – Tolgo tutte le parentesi aperte a b / c – d e * + a c * –
La valutazione delle espressioni Come si può realizzare tutto ciò in c++ o c? I passi da da svolgere sono i seguenti: A+b*c ==(a+(b*c)) == abc*+ Tutto ciò, e cioè passare dalla notazione infix alla notazione postfix si può risolvere grazie alla implementazione con gli stack Vediamo in che modo: Prendo l’ espressione e la scorro con un ciclo Per ogni elemento dell’ espressione controllo se e un operatore o un operando prendendo a seconda del caso le seguenti decisioni:
La valutazione delle espressioni Se l’ elemento letto e un operando allora lo posso scrivere in out nell' array che memorizzerà la mia espressione postfix Se l’ elemento letto e un operatore allora lo salvo nello stack.Prima di salvare pero controllo se l’ elemento che sto inserendo ha una priorità maggiore dell’ elemento che sta alla testa dello stack,se cosi e allora lo salvo,altrimenti devo vuotare lo stack e salvare l’elemento che tolgo in out (nell' array che memorizza l’ espressione postfix) finche l’elemento alla testa dello stack non ha una priorità minore dell’ elemento da inserire.
La valutazione delle espressioni Vediamo meglio l’ algoritmo passo – passo: Espressione stack[0] stack[1] stack[2] out(vect) a a + + a b + ab * + * ab c + * abc A questo punto svuoto lo stack e salvo in out e ottengo Out(vector)=abc*+
La valutazione delle espressioni Complichiamo l’ algoritmo passo – passo: Espressione stack[0] stack[1] stack[2] out(vect) a a * * a b * ab + + ab* c + ab*c A questo punto svuoto lo stack e salvo in out e ottengo Out(vector)=ab*c+
La valutazione delle espressioni Complichiamo l’ algoritmo passo – passo: Espressione stack[0] stack[1] stack[2] out(vect) a a * * a b * ab + + ab* c + ab*c A questo punto svuoto lo stack e salvo in out e ottengo Out(vector)=ab*c+ Ho tolto un elemento dallo stack, precisamente “*” e lo ho salvato in out, il vettore che memorizza la mia espressione postfix.Al posto di * ho salvato nello stack + che ha una priorità più bassa.
La valutazione delle espressioni con parentesi Le parentesi rendono un po' più difficile il processo di trasformazione di un espressione infissa, in quanto l’ espressione post fissa equivalente e priva di parentesi.Come esempio useremo l’ espressione a*(b+c)*d che trasformata in espressione postfissa diventa abc+*d*.Nella prossima slide vediamo il processo di conversione. Si noti che gli operatori interni alle parentesi vengono inseriti nello stack finche non viene raggiunta la parentesi destra che ha una bassa priorità.a questo punto lo stack viene svuotato finche non viene raggiunta la corrispondente parentesi sinistra;anche la parentesi sinistra viene cancellata dallo stack ma non viene salvata in out(la parentesi destra non sarà mai inserita nello stack).Fatto questo, nell’espressione infissa in esame rimane da esaminare solo il “*d”.Poche le due moltiplicazioni, e cioè quella alla testa dello stack e quella di *d hanno la stessa priorità, la prima viene indirizzata in out prima di d e la seconda posta nello stack ed estratta dopo che d passa all’ out
La valutazione delle espressioni con parentesi L’ analisi dei due esempi suggerisce uno schema basato su livelli di precedenza per inserire ed estrarre operatori dallo stack.La parentesi sinistra complica le cose in quanto si comporta come un operatore di bassa priorità quando si trova nello stack e come operatore di alta priorità quando è fuori dallo stack.Essa viene inserita nello stack tutte le volte che viene raggiunta nell’ espressione ed eliminata dallo stack soltanto quando viene raggiunta la corrispondente parentesi destra(ciò e dovuto al fatto che la parentesi destra nello stack ha una priorità bassa ma superiore a quella della parentesi sinistra). Pertanto abbiamo due tipi di priorità una dentro la stack ed una fuori.
La valutazione delle espressioni con parentesi Algoritmo passo – passo: Espressione stack[0] stack[1] stack[2] out(vect) a a * * a ( * ( a b * ( ab + * ( + ab c * ( + abc ) * abc+ * * abc+* d * abc+*
La valutazione delle espressioni con parentesi A questo punto svuoto lo stack e ottengo: Abc+*d*