700 likes | 851 Views
CAPITOLO 17. Possono scegliere questo progetto solo gli studenti che hanno superato la prova del progetto di intercorso. Siano dati tre distributori A,B,C, di bevande o cibo. Caricare nei distributori i prodotti con date di scadenza non ordinate.
E N D
Possono scegliere questo progetto solo gli studenti che hanno superato la prova del progetto di intercorso. Siano dati tre distributori A,B,C, di bevande o cibo. Caricare nei distributori i prodotti con date di scadenza non ordinate. Simulare l’attività di vendita giornaliera come segue: a inizio giornata si eliminano dalla coda di ogni distributore i prodotti scaduti scaricandoli in unico contenitore (stack). Quindi si effettua la vendita. A fine settimana estrarre dal contenitore prima i prodotti di tipo B, poi C e infine A caricandoli nell’ordine su un camion (altro stack). Le strutture dati da adoperare sono: per i distributori di prodotti code con liste legate, per il contenitore e il camion stack realizzati con liste legate. Implementare e utilizzare le Unit ADTQ e ADTS per code PROGETTO MODULO B – a.a. 2000-2001
Simulazione di prenotazione e vendita biglietti teatrali. Supponiamo di dover prenotare e vendere biglietti per uno spettacolo teatrale. Il teatro ha tre ordini di posti: A – prima fila con 10 posti B – sala con 50 posti C – loggione con 30 posti Simulare la vendita al botteghino. Siano N gli spettatori in coda. Vendere i biglietti agli spettatori in coda prenotando per loro il posto richiesto se libero. Ogni spettatore è rappresentato attraverso una struttura record del tipo Cognome, Età, Posto richiesto, Posto ottenuto. La coda allo sportello viene creata prima della vendita (i dati possono anche stare su un file). Ad inizio simulazione si caricano i dati della coda in una struttura a coda con lista legata. Si inizia la vendita. Ad ogni richiesta si controlla se è disponibile il posto richiesto. In caso affermativo si trasferisce il record dalla struttura a coda in una struttura a lista legata diversa per ogni ordine di posto. Se il posto non è disponibile si propone un posto in una posizione diversa. Se lo spettatore accetta si prosegue altrimenti lo si colloca in una lista di attesa. E’ necessario prevedere le seguenti situazioni: Uno spettatore abbandona la coda. Uno spettatore in coda è servito prima perché raccomandato. Uno spettatore disdice il posto acquistato. Uno spettatore cambia ordine di posto. Fornire la lista degli spettatori in ogni ordine di posto. Fornire la lista degli spettatori in coda al botteghino. Fornire la lista degli spettatori nella lista di attesa. Le strutture da adoperare sono: Una coda realizzata con una lista legata. Una lista legata per i posti di tipo A. Una lista legata per i posti di tipo B. Una lista legata per i posti di tipo C. Una coda per la lista di attesa. Implementare e utilizzare le Unit ADTQ e ADTL per code e liste. PROGETTO MODULO B – a.a. 2000-2001
a b c c d e LISTE E PUNTATORI Una lista può essere vista come un array. Per la manipolazione degli array sono stati introdotti gli ADT delle code e degli stack, lo stesso faremo con le liste. Una lista può anche essere vista come una serie di elementi gli uni collegati agli altri attraverso un sistema di puntatori. Le strutture a,b,…., possono essere di type integer, stringa, record, coda, stack, etc.
item puntatore puntatore Variabile dinamica Pt nodo P1 Luca P2 Ugo P3 ? Emma Una linear linked list ( o lista legata lineare) è una collezione di variabili dinamiche formate da un campo item e un campo puntatore. Ogni puntatore punta alla variabile successiva nell’ambito della struttura considerata.
Next Item Pt Emma Px ? Stringa di 20 caratteri CONST NullItem= ' ' ; {controllo di eventuali errori } TYPE ItemType= STRING20[20] LNodeP=^LNodeType {puntatore a un nodo della lista} {variabile nodo LNodeType = RECORD è anonima} Item:ItemType; Next:LNodeP END; VAR Px:LNodeP; Notare che l’identificatore LNodeP è definito prima del record dinamico LNodeType. Questa è una eccezione rispetto allo standard del Pascal in cui si fa riferimento a un Type che precede e non che segue.
Next Px P1 Luca P2 Ugo P3 Emma NIL Item Item Next CONST NullItem= ' ' ; {controllo di eventuali errori } TYPE ItemType= STRING20[20] LNodeP=^LNodeType LNodeType = RECORD Item:ItemType; Next:LNodeP END; VAR Px:LNodeP; Px^.Item Emma Px^.Next^.Item Luca Px^.Next^.Next^.Item Ugo Px^.Next^.Next ^.Next^.Next NIL
Obiettivo: progettare una ADT per le code ADTQ e una per gli stack ADTS utilizzando strutture del tipo Linear linked list. UNITADTxxxxx; {documentazione} INTERFACE {sezione interfaccia} {definizioni dell’ADT} TYPE …………………. END; { le operazioni: primitive (constructor o selector), non primitive, predicati } PROCEDURE …………………….. FUNCTION …………………………. IMPLEMENTATION {sezione implementazioni} PROCEDURE …………………….. FUNCTION ………………………….
Per le linear linked list vi sono operazioni che possono essere applicate a un qualunque nodo della lista. Queste primitive servono a gestire qualunque nodo e a implementare liste particolari come le code e gli stack. • Vi sono solo quattro operazioni nell’insieme delle primitive: • constructor • creazione di un nuovo nodo con un valore assegnato al campo dati (Item) e NIL al campo link (Next) • dispose (dealloca) di un nodo supposto che esso esista come variabile dinamica • selector • selezione il campo dati (item) • seleziona il campo puntatore (next)
CONST NullItem= ' ' ; {controllo di eventuali errori } TYPE ItemType= STRING20[20] LNodeP=^LNodeType LNodeType = RECORD Item:ItemType; Next:LNodeP END; VAR Px:LNodeP; Item Next Node INTERFACE PROCEDURE MakeNode(AnItem:ItemType; VAR Node:LNodeP); {Primitive constructor: Crea un nuovo nodo, assegnando a AnItem il valore per il campo Item e NIL al campo puntatore Next. } PROCEDURE KillNode(VAR Node:LNodeP); {Constructor :se Node non è NIL, dispose la memoria allocata per il Node e poi pone il Node a NIL. } PROCEDURE ItemValue(Node:LNodeP; VAR AnItem:ItemType); {Primitive Selector :ritorna il valore di AnItem per un dato Node; ritorna NullItem se il valore di Node è NIL indicando che esso rappresenta il nodo di partenza di una lista vuota} FUNCTION NextNode(Node:LNodeP) : LNodeType; {assegnato un nodo ritorna il nodo successivo inteso come la parte di lista che ordinatamente segue il nodo in esame. Se il Node è NIL allora ritorna la lista vuota }
Node Item Next PROCEDURE MakeNode(AnItem:ItemType; VAR Node:LNodeP); BEGIN new(Node); Node^.Item=AnItem; Node^.Next:=NIL END; PROCEDURE KillNode(VAR Node:LNodeP); BEGIN IF Node <> NIL THEN BEGIN dispose(Node); Node:=NIL END END; CONST NullItem= ' ' ; {controllo di eventuali errori } TYPE ItemType= STRING20[20] LNodeP=^LNodeType LNodeType = RECORD Item:ItemType; Next:LNodeP END; VAR Px:LNodeP; Node:LNodeP;
Node Item Next PROCEDURE ItemValue(Node:LNodeP; VAR AnItem:ItemType); BEGIN IF Node <> NIL THEN AnItem := Node^.Item ELSE AnItem := NullItem END; FUNCTION NextNode(Node:LNodeP) : LNodeType; BEGIN IF Node <> NIL THEN NextNode := Node^.Next ELSE NextNode := NIL END; CONST NullItem= ' ' ; {controllo di eventuali errori } TYPE ItemType= STRING20[20] LNodeP=^LNodeType LNodeType = RECORD Item:ItemType; Next:LNodeP END; VAR Px:LNodeP; Node:LNodeP;
ESEMPIO Mostrare tutti i valori delle variabili dinamiche contenute in una lista a partire da un preassegnato nodo. Soluzione iterativa PROCEDURE ShowList(Px:LNodeP); VAR AName:ItemType; BEGIN ItemValue(Px,AName) WHILE AName <> NullItem DO BEGIN writeln(AName); Px:=NextNode(Px); ItemValue(Px), AName) END END; Soluzione ricorsiva PROCEDURE ShowList(Px:LNodeP); VAR AName:ItemType; BEGIN ItemValue(Px,AName) If AName <> NullItem THEN BEGIN writeln(AName); ShowList(NextNode(Px)) END END; CONST NullItem= ' ' ; {controllo di eventuali errori } TYPE ItemType= STRING20[20] LNodeP=^LNodeType LNodeType = RECORD Item:ItemType; Next:LNodeP END; VAR Px:LNodeP; Node:LNodeP;
Queue Betty ItemsOnQueue 5 Head Tail Tom Head Head Dick Harry John Alice Tail Betty Tom Dick Harry John Alice Le code come linked list
CONST NullItem= ' ' ; TYPE ItemType= STRING20[20] LNodeP=^LNodeType LNodeType = RECORD Item:ItemType; Next:LNodeP END; QType = RECORD ItemsOnQueue:integer; Head, Tail: LNodeP END; LNodeP Head ItemsOnQueue Tail LNodeType QType Item Next Item Next Una ADTQType Nella logica delle code Head^ diventa il primo nodo da dereferenziare La struttura della coda ha tre campi: ItemOnQueue : integer numero elementi in coda Head: LNodeP puntatore al primo elemento della coda Tail: LNodeP puntatore all’ultimo elemento della coda
INTERFACE Operazioni sui nodi PROCEDURE MakeNode(AnItem:ItemType; VAR Node:LNodeP); {Primitive constructor: Crea un nuovo nodo, assegnando a AnItem il valore per il campo Item e NIL al campo puntatore Next. PROCEDURE KillNode(VAR Node:LNodeP); {Constructor :se Node non è NIL, dispose la memoria allocata per il Node e poi pone il Node a NIL. PROCEDURE ItemValue(Node:LNodeP; VAR AnItem:ItemType); {Primitive Selector :ritorna il valore di AnItem per un dato Node; ritorna NullItem se il valore di Node è NIL indicando che esso rappresenta il nodo di partenza di una lista vuota} FUNCTION NextNode(Node:LNodeP) : LNodeType; {assegnato un nodo ritorna il nodo successivo inteso come la parte di lista che ordinatamente segue il nodo in esame. Se il Node è NIL allora ritorna la lista vuota } PROCEDURE MakeQueue(VAR Queue:QType); {Inizializza la coda } PROCEDURE AddQueue(AnItem: ItemType; VAR Queue:QType); {Aggiunge un item alla coda } PROCEDURE DeleteQueue(VAR Queue:QType); {Se la coda non è vuota cancella il primo item, altrimenti non fa nulla }
QType = RECORD ItemsOnQueue:integer; Head, Tail: LNodeP END; Head ItemsOnQueue Tail QType Item Next Item Next FUNCTION FirstOnQueue(Queue:QType): LNodeP; {Se la coda non è vuota fornisce il primo item, altrimenti da NIL } FUNCTION QCount(Queue:QType):integer; {Fornisce il numero di oggetti che sono in coda } FUNCTION QEmpty(Queue:QType):boolean; {E’ vera se non ci sono item in coda } IMPLEMENTATION PROCEDURE MakeQueue(VAR Queue:QType); {Inizializza la coda } BEGIN WITH Queue DO BEGIN ItemsOnQueue:=0 Head:=NIL; Tail:=NIL END; END;
QType = RECORD ItemsOnQueue:integer; Head, Tail: LNodeP END; Head ItemsOnQueue Tail QType Item Next Item Next FUNCTION FirstOnQueue(Queue:QType): LNodeP; {Se la coda non è vuota fornisce il primo item, altrimenti da NIL } BEGIN FirsOnQueue:=Queue.Head END; FUNCTION QCount(Queue:QType):integer; {Fornisce il numero di oggetti che sono in coda } BEGIN QCount:=Queue.ItemsOnQueue END; FUNCTION QEmpty(Queue:QType):boolean; {E’ vera se non ci sono item in coda } BEGIN QEmpty:=Queue.Head=NIL END;
Punta al nuovo nodo Temp AnItem Next QType = RECORD ItemsOnQueue:integer; Head, Tail: LNodeP END; Head ItemsOnQueue Tail QType Item Next Item Next Progettiamo AddQueue. Per aggiungere un nodo contenente il valore di AnItem alla coda in primo luogo bisogna costruire il nodo (MakeNode). Questo avrà il campo Next=NIL e sarà quindi aggiunto alla coda dopo il nodo Tail^. Quindi il valore di Tail sarà assegnato al nuovo nodo. Pseudo Codice. MakeNode(AnItem, Temp) WITH Queue DO collega il nodo Temp al resto della coda Tail Temp ItemsOnQueue ItemsOnQueue + 1
Queue Temp Joe NIL Alice Joe Head ItemsOnQueue Tail Item Next Item Next La variabile locale Temp è di tipo LNodeP. Sebbene essa sia dichiarata e creata localmente il suo valore così come il valore della relativa variabile dinamica sopravvive oltre il blocco AddQueue a causa dell’operazione Tail Temp. Se la coda non è vuota è possibile collegare direttamente il nodo usando l’istruzione Tail^.Next:=Temp
Temp Queue Joe NIL ItemsOnQueue 1 Head Tail NIL Se la coda è vuota i valori assegnati a Head e Tail sono entrambi NIL. In questo caso la coda con un solo item è creata dalla assegnazione Head:=Temp e Tail:=Head
Queue Temp Joe NIL Alice Joe Head ItemsOnQueue Tail Item Next Item Next Se la coda non è vuota si deve indirizzare il puntatore dell’ultimo elemento in coda Tail^.Next all’area puntata da Temp e altrettanto deve fare Tail che deve puntare all’area di Temp. Quindi IF Head = NIL THEN Head=Temp ELSE Tail =Temp^.Next Tail:=Temp
Item Next Temp QType Head ItemsOnQueue Tail Item Next Item Next PROCEDURE AddQueue(AnItem: ItemType; VAR Queue:QType); {Aggiunge un item alla coda } VAR Temp:LNodeP; BEGIN MakeNode(AnItem,Temp); WITH Queue DO BEGIN IF Head=NIL THEN Head:=Temp ELSE Tail^.Next:=Temp; Tail:=Temp; ItemsOnQueue:= ItemsOnQueue+1 END END; CONST NullItem= ' ' ; TYPE ItemType= STRING20[20] LNodeP=^LNodeType LNodeType = RECORD Item:ItemType; Next:LNodeP END; QType = RECORD ItemsOnQueue:integer; Head, Tail: LNodeP END;
Item Next Temp Memorizza il puntatore del nodo da deallocare Caso in cui in coda c’era solo un item. Head ItemsOnQueue Tail QType Item Next Item Next Progettiamo DeleteQueue. Se la coda ha un item la postcondizione di DeleteQueue è che il suo Head è stato cancellato e un altro nodo è diventato Head. Ovviamente il vecchio nodo Head non servirà più e quindi su esso si applicherà una operazione di dispose. Pseudo Codice. Temp Queue.Head IF Temp <> NIL THEN WITH Queue DO assegna un nuovo valore a Head KillNode(Temp) ItemsOnQueue ItemsOnQueue - 1 Head Temp^.Next IF Head NIL THEN Tail NIL
PROCEDURE DeleteQueue(VAR Queue:QType); {Se la coda non è vuota cancella il primo item, altrimenti non fa nulla } VAR Temp: LNodeP; BEGIN Temp:=Queue.Head; IF Temp <> NIL THEN WITH Queue DO BEGIN Head:=Temp^.Next; IF Head = NIL THEN Tail:=NIL; dispose(Temp); ItemsOnQueue:= ItemsOnQueue-1 END END; CONST NullItem= ' ' ; TYPE ItemType= STRING20[20] LNodeP=^LNodeType LNodeType = RECORD Item:ItemType; Next:LNodeP END; QType = RECORD ItemsOnQueue:integer; Head, Tail: LNodeP END;
Carla Lucio Ugo Maria Alice Data una coda di oggetti si vuole sapere in quale posizione nella coda si trova l’oggetto X. ESEMPIO Si vuole sapere Ugo in che posizione sta. A tal fine possiamo costruire una FUNCTION QPos(Queue,’Ugo’) che restituisce la posizione di Ugo e la mostra attraverso una istruzione del tipo writeln(‘La posizione di Ugo in coda è ‘; QPos(Queue,’Ugo’))
FUNCTION QPos(Queue:Qtype; SearchItem:ItemType): integer; {Se la coda non è vuota ritorna il nodo che rappresnta il primo item nella coda; se la coda è vuota ritorna NIL } VAR CandNode: LNodeP; CandItem:ItemType; CandPos:integer; BEGIN CandNode:=FirstOnQueue(Queue); {il primo item nella coda o NIL} ItemValue(CandNode,CandItem); CandPos:=1; WHILE (CandItem <> NullItem) AND (CandItem <> SearchItem) DO BEGIN CandNode:=NextNode(CandNode); ItemValue (CandNode,CandItem); CandPos:=CandPos+1; END; IF CandItem=SearchItem THEN Qpos:=CandPos ELSE Qpos:=0 END; CONST NullItem= ' ' ; TYPE ItemType= STRING20[20] LNodeP=^LNodeType LNodeType = RECORD Item:ItemType; Next:LNodeP END; QType = RECORD ItemsOnQueue:integer; Head, Tail: LNodeP END;
PROGRAM TestCodeListe; USES ADTQ; VAR Coda:QType; Nome:ItemType; Nelem, Ncont:integer; BEGIN writeln(' CREA CODA'); MakeQueue(Coda); writeln(' Dammi un nome'); readln(Nome); WHILE Nome<> NullItem DO BEGIN AddQueue(Nome,Coda); writeln(' Dammi un nome '); readln(Nome); END; ShowList(FirstOnQueue(Coda)); writeln('In coda ci sono ',QCount(Coda)); WITH Coda DO BEGIN writeln(' Quanti elementi vuoi cancellare? '); readln(Nelem); Ncont:=0; WHILE ((Head<>NIL) AND (Ncont<>Nelem)) DO BEGIN readln; Ncont:=Ncont+1; ItemValue(Coda.Head,Nome); writeln('Cancello ',Nome); DeleteQueue(Coda); ShowList(FirstOnQueue(Coda)); END; writeln(' LISTA FINALE '); ShowList(FirstOnQueue(Coda)); writeln(' Cerca l''elemento '); readln(Nome); writeln(' L''elemento ' , Nome,' e'' in ', QPos(Coda, Nome), ' posizione'); IF QEmpty(Coda) THEN writeln(' La coda e'' vuota') ELSE writeln(' In coda ci sono ',QCount(Coda),' elementi'); END; END. CONST NullItem= ' ' ; TYPE ItemType= STRING20[20] LNodeP=^LNodeType LNodeType = RECORD Item:ItemType; Next:LNodeP END; QType = RECORD ItemsOnQueue:integer; Head, Tail: LNodeP END;
GLI STACK COME LINKED LIST Obiettivo progettare una ADT per uno stack di integer usando le liste. • Operazioni previste • MakeStack primitive constructor che crea uno stack vuoto • Push constructor per inserire un item nello stack • Pop constructor per estrarre un elemento dalla testa dello stack • TopItem primitive selector che ritorna il valore dell’item che è in testa allo stack • StackEmpty predicate che ritorna TRUE se non vi sono item nello stack. N.B. Se si cerca di estrarre un elemento da una lista vuota non deve succedere niente. Associamo il valore di maxint a TopItem quando abbiamo a che fare con una lista vuota Lo Stack ADT non è altro che il puntatore all’item che è sul top.
TOP Item Next INTERFACE CONST NullItem=maxint; TYPE StkP=^StkNode; ItemType=integer; StkNode= RECORD Item:ItemType; Next:StkP END; StkType = RECORD Top:StkP END; GLI OPERATORI PROCEDURE MakeNode(AnItem:ItemType; VAR ANode:StkP); {Primitive constructor: Crea un nuovo nodo, assegnando a AnItem il valore per il campo Item e NIL al campo puntatore Next. PROCEDURE KillNode(VAR ANode:StkP);} {Constructor :se Node non è NIL, dispose la memoria allocata per il Node e poi pone il Node a NIL}
7 5 5 Stack.Top Stack.Top 7 PROCEDURE MakeStack(VAR Stack:StkType);} {Constructor :crea uno Stack vuoto} PROCEDURE Push(AnItem:ItemType; VAR Stack:StkType); {Inserisce il valore di AnItem nello Stack)} PROCEDURE Pop(VAR Stack:StkType); {Estra dal top il valore di AnItem. Se lo Stack è vuoto non fa nulla)} FUNCTION TopItem(Stack:StkType)ItemType; {Restituisce il valore dell’item che è nel top dello Stack. Se lo stack è vuoto restituisce maxint)} FUNCTION StackEmpty(Stack:StkType)boolean; {Restituisce TRUE se non vi sono item nello Stack.}
Stack.Top PROCEDURE MakeStack(VAR Stack:StkType);} {Constructor :crea uno Stack vuoto} BEGIN Stack.Top:=NIL END; FUNCTION TopItem(Stack:StkType)ItemType; {Restituisce il valore dell’item che è nel top dello Stack. Se lo stack è vuoto restituisce maxint)} BEGIN WITH Stack DO IF Top <> NIL THEN TopItem:=Top^.Item ELSE TopItem:=NullItem END; FUNCTION StackEmpty(Stack:StkType)boolean; {Restituisce TRUE se non vi sono item nello Stack.} BEGIN StackEmpty:= StackTOP = NIL END;
Stack.Top 5 Temp Temp Stack.Top 7 5 5 7 Heap Stack.Top Temp 7 Se lo stack è vuoto Temp e quindi alla fine anche Stack.Top puntano a NIL. PROCEDURE Push(AnItem:ItemType; VAR Stack:StkType); {Inserisce il valore di AnItem nello Stack} VAR Temp:StkP; BEGIN MakeNode(AnItem,Temp); {Creo Temp=AnItem } Temp^.Next:=Stack.Top; {Assegno al puntatore di Temp il puntatore di StackTop } Stack.Top:= Temp {Stac.Top punta a Temp } END;
Temp Temp Stack.Top 7 Temp Stack.Top 7 5 5 5 7 Heap Stack.Top Se lo stack è vuoto non si fa nulla. PROCEDURE Pop(VAR Stack:StkType); {Elimina dal top il valore di AnItem. Se lo Stack è vuoto non fa nulla)} VAR Temp:StkP; BEGIN WITH Stack DO IF Top <> NIL THEN BEGIN Temp:=Top; Top:=Temp^Next; KillNode(Temp) END; END;
CONST NullItem= ' ' ; TYPE ItemType= STRING20[20] LNodeP=^LNodeType LNodeType = RECORD Item:ItemType; Next:LNodeP END; PROGRAM TestStackListe; USES ADTSTK; VAR Stack:StkType; Nome:ItemType; Nelem, Ncont:integer; BEGIN writeln(' CREA STACK'); MakeStack(Stack); writeln; writeln(' Dammi un nome'); readln(Nome); WHILE Nome<> NullItem DO BEGIN Push(Nome,Stack); writeln(' Dammi un nome '); readln(Nome); END; ShowList(Stack.Top); QType = RECORD ItemsOnQueue:integer; Head, Tail: LNodeP END; WITH Stack DO BEGIN writeln(' Quanti elementi vuoi cancellare? '); readln(Nelem); Ncont:=0; WHILE ((Top<>NIL) AND (Ncont<>Nelem)) DO BEGIN readln; Ncont:=Ncont+1; ItemValue(Stack.Top,Nome); ShowList(Top); writeln('Vado a cancellare ',Nome); Pop(Stack); END; writeln(' FINE CANCELLAZIONE '); writeln(' LISTA FINALE '); ShowList(Top); END; END.
ESERCIZIO Scrivere un algoritmo per il calcolo di una funzione tale che: ricevute in ingresso due variabili S e Z di tipo stringa calcola il numero delle occorrenze di S in Z. Esempio: S=aa Z=ccbaaabaa La funzione restituisce 3.
* + - 7 5 9 8 LE ESPRESSIONI ARITMETICHE Una espressione aritmetica del tipo (7+5)*(9-8) si può rappresentare attraverso un albero di computazione come segue. Percorrendo l’albero da sinistra a destra si ha 7+5*9-8 che secondo le convenzioni della aritmetica fornisce il risultato di 44. Se però ad ogni livello dell’albero introduciamo delle parentesi il risultato che otterremo sarà ((7+5)*(9-8)) il cui valore 12 sarà identico a quello che otterremmo valutando l’espressione di partenza. La notazione in cui i singoli termini vengono raccolti facendo uso di parentesi e sono rappresentati come sopra si chiama notazione infissa. Questa notazione è non ambigua.
Un’altra maniera per rappresentare espressioni aritmetica è la cosiddetta espressione polacca inversa introdotta dal polacco Jan Lukasiewicz nel 1951. Questa notazione ci permette di scrivere in modo non ambiguo una espressione senza adoperare le parentesi. Ricordando che ogni operatore aritmetico (+,-,*,/) è un operatore binario, si applica cioè a due operandi, avremo che posto della notazione infissa a + b scriveremo nella notazione polacca inversa a b + Ogni operatore binario deve quindi essere preceduto dal primo e dal secondo operando Allora (7+5)*(9-8) si scriverà: 7 5 + 9 8 - * Nello scrivere una espressione in notazione polacca inversa o postfissa adopereremo / al posto di DIV e \ al posto di MOD
Esempio: calcolare il valore dell’espressione: 7 3 5 + * 3 1 + / 7 8 * 3 1 + / 56 3 1 + / 56 4 / 14
Algoritmo Si legga l’espressione in notazione polacca inversa. Se il termine letto è un intero allora si inserisce nello stack. Se il termine letto è un operatore allora gli ultimi due termini inseriti nello stack vengono estratti e l’operatore viene applicato ad essi. Il risultato dell operazione viene inserita nello stack. Quando tutte le operazioni sono state applicate allora il risultato finale dell’espressione si troverà nel top dello stack.
- \ + 8 6 1 4 5 8 8 8 1 3 8 3 4 7 6 6 Applichiamo l’algoritmo all’espressione 8 6 1 - \ 4 +
Pseudo codice MakeStack(InStack) WHILE NOT eoln DO SkipBlanks(Ch) IF Ch is a digit THEN GetInteger(Ch,Int) Push(Int,IntStack) ELSE IF Ch is an operator THEN ApplyOperation(Ch,IntStack) ELSE IF NOT eoln THEN Push(NullItem,IntStack) readln ShowValue(IntStack)
PROGRAM CalcolatoreRPN(input,output); Uses StackADT; VAR IntStack:StackType; Ch:char; Int:integer; ………………………... BEGIN MakeStack(IntStack); WHILE NOT eoln DO BEGIN SkipBlanks(Ch); IF Ch IN [‘0’..’9’] THEN BEGIN GetInteger(Ch,Int); Push(Int,IntStack) END ELSE IF Ch IN [‘+’,’-’,’*’,’/’,’\’] THEN ApplyOperation(Ch,IntStack) ELSE IF NOT eoln THEN Push(NullItem,IntStack) END; readln; ShowValue(Intstack) END.
PROCEDURE SkipBlanks(VAR Ch:char); BEGIN Ch:=‘ ‘; WHILE (Ch=‘ ‘) AND NOT eoln DO read(Ch) END;
PROCEDURE GetInteger(Ch:char;VAR Int:ItemType); BEGIN Int := 0; WHILE Ch IN [‘0’..’9’] DO BEGIN Int:= Int*10 +ord(Ch) – ord(‘0’); IF NOT eoln THEN read(Ch) ELSE Ch:=‘ ‘ END; IF Ch <> ’ ‘ THEN Int := NullItem END;
Pseudo Codice ApplyOperation Operand2 TopItem(IntStack) Pop(IntStack) Operand1 TopItem(IntStack) Pop(IntStack) IF (Operand2 = NullItem) OR (Operand1 = NullItem) THEN Push(NullItem,IntStack) ELSE Result applica l’operatore ai due operandi Push(Result,IntStack)
PROCEDURE ApplyOperation(Operator:char; VAR IntStack:StkType); VAR Operand1, Operand2, Result: integer; BEGIN Operand2:=TopItem(IntStack); Pop(IntStack); Operand1:=TopItem(IntStack); Pop(IntStack); IF (Operand1=NullItem OR (Operand2=NullItem) THEN Push(NullItem,IntStack) ELSE BEGIN CASE Operator OF ‘+’: Result:=Operand1 + Operand2; ‘-’: Result:=Operand1 - Operand2; ‘*’: Result:=Operand1 * Operand2; ‘/’: Result:=Operand1 DIV Operand2; ‘\’: Result:=Operand1 MOD Operand2; END; Push(Result,IntStack) END END;
PROCEDURE ShowValue(IntStack:StkType); VAR Result: integer; BEGIN Result:=TopItem(IntStack); Pop(IntStack); IF (Result=NullItem OR NOT StackEmpty(IntStack) THEN writeln(‘ L’espressione è scritta male ‘) ELSE writeln(Result:1) END;
LISTE GENERALIZZATE Si vuole realizzare una ADT per le liste mediante la quale sia possibile aggiungere o eliminare nodi dalla lista in qualunque suo punto e non solo in testa o in coda come nel caso delle liste legate lineari (code e stack) fin qui viste. A questo fine è necessario aggiungere un altro parametro nelle procedure di AddNode e DeleteNode che tenga conto della posizione del nodo da aggiungere o da eliminare rispetto alla lista. Questo può avvenire utilizzando opportunamente un puntatore.
NullItem Next INTERFACE PROCEDURE MakeList(VAR AList:ListType); {Crea una nuova lista vuota} PROCEDURE InsertNode(AnItem:ItemType; PrevNodeP:LNodeP; VAR AList:ListType); {Inserisce un Node con campo AnItem nella lista Alist. Il nodo è inserito subito dopo il nodo che ha come puntatore PrevNodeP. Se AListFirst=NIL allora il nodo sarà il primo della lista} PROCEDURE DeleteNode(PrevNodeP:LNodeP; VAR AList:ListType); {Cancella ilNodo che nella lista segue quello puntato da PrevNodeP . Se PrevNodeP è Alist.First, viene cancellato il primo nodo. Se la lista è vuota o PrevNodeP=NIL allora non succede nulla } CONST NullItem= ' ' ; {controllo di eventuali errori } TYPE ItemType= STRING[20] LNodeP=^LNodeType LNodeType = RECORD Item:ItemType; Next:LNodeP END; ListType = RECORD First:LNodeP END; VAR ListFirst