CAPITOLO 17
This presentation is the property of its rightful owner.
Sponsored Links
1 / 70

CAPITOLO 17 PowerPoint PPT Presentation


  • 68 Views
  • Uploaded on
  • Presentation posted in: General

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.

Download Presentation

CAPITOLO 17

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


Capitolo 17

CAPITOLO 17


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.

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


Capitolo 17

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


Capitolo 17

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.


Capitolo 17

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.


Capitolo 17

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 nodoLNodeType = 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.


Capitolo 17

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^.ItemEmma

Px^.Next^.ItemLuca

Px^.Next^.Next^.ItemUgo

Px^.Next^.Next ^.Next^.NextNIL


Capitolo 17

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 ………………………….


Capitolo 17

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)


Capitolo 17

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 }


Capitolo 17

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;


Capitolo 17

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;


Capitolo 17

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;


Capitolo 17

Queue

Betty

ItemsOnQueue 5

HeadTail

Tom

Head

Head

Dick

Harry

John

Alice

Tail

Betty

Tom

Dick

Harry

John

Alice

Le code come linked list


Capitolo 17

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 : integernumero elementi in coda

Head: LNodePpuntatore al primo elemento della coda

Tail: LNodePpuntatore all’ultimo elemento della coda


Capitolo 17

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 }


Capitolo 17

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;


Capitolo 17

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;


Capitolo 17

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


Capitolo 17

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


Capitolo 17

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:=TempeTail:=Head


Capitolo 17

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


Capitolo 17

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;


Capitolo 17

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


Capitolo 17

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;


Capitolo 17

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’))


Capitolo 17

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;


Capitolo 17

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;


Capitolo 17

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.


Capitolo 17

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}


Capitolo 17

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.}


Capitolo 17

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;


Capitolo 17

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;


Capitolo 17

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;


Capitolo 17

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.


Capitolo 17

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.


Capitolo 17

*

+

-

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-8che 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.


Capitolo 17

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


Capitolo 17

Esempio: calcolare il valore dell’espressione:

7 3 5 + * 3 1 + /

7 8 * 3 1 + /

56 3 1 + /

56 4 /

14


Capitolo 17

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.


Capitolo 17

-

\

+

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 +


Capitolo 17

Pseudo codice

MakeStack(InStack)

WHILE NOT eoln DO

SkipBlanks(Ch)

IF Ch is a digit THEN

GetInteger(Ch,Int)

Push(Int,IntStack)

ELSEIF Ch is an operator THEN

ApplyOperation(Ch,IntStack)

ELSEIF NOT eoln THEN

Push(NullItem,IntStack)

readln

ShowValue(IntStack)


Capitolo 17

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.


Capitolo 17

PROCEDURE SkipBlanks(VAR Ch:char); BEGIN

Ch:=‘ ‘;

WHILE (Ch=‘ ‘) AND NOT eoln DO read(Ch)

END;


Capitolo 17

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;


Capitolo 17

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)


Capitolo 17

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;


Capitolo 17

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;


Capitolo 17

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.


Capitolo 17

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


Capitolo 17

FUNCTION FirstNode(AList:ListType) :LNodeP;

{ritorna il puntatore del primo nodo della lista }

FUNCTION EmptyList(AList:ListType) :boolean;

{ritorna TRUE se la lista è vuota }

FUNCTION CercaPrevP(Px:LNodeP; VAR AList:ListType):LNodeP;

{dato il puntatore di un nodo Px fornisce il valore del puntatore del nodo che lo precede}

FUNCTION LPos(List:Listtype; SearchItem:ItemType):LNodeP;

{Fornisce il puntatore di un preassegnato nodo SearchItem}

FUNCTION Seleziona(AList:ListType;Index:integer):ItemType;

{Fornisce il nome del nodo che si trova al posto Index}

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

AList:ListType;


Capitolo 17

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

AList:ListType;

AListFirst

NullItem

Next

PROCEDURE MakeList(VAR AList:ListType);

{Crea una nuova lista vuota mettendo nei campi di First rispettivamente NullItem e NIL }

BEGIN

MakeNode(NullItem,AList.First);

END;END;

FUNCTION FirstNode(AList:ListType) :LNodeP;

{ritorna il puntatore del primo nodo della lista }

BEGIN

FirstNode:=ALIst.First^.Next

END;

FUNCTION EmptyList(AList:ListType) :boolean;

{ritorna TRUE se la lista è vuota }

BEGIN

EmptyList:=AList.First^.Next=NIL

END;


Capitolo 17

AListFirst

NIL

Temp

Temp

PrevNodeP

AListFirst

AListFirst

Item

Item

Item

Item

Item

Item

Item

Item

Item

Next

Next

Next

Next

Next

Next

Next

Next

NIL

Temp

PrevNodeP

PrevNodeP

PROCEDURE InsertNode(AnItem:ItemType;PrevNodeP:LNodeP; VAR AList:ListType);

VAR

Temp:LNodeP;

BEGIN

MakeNode(AnItem,Temp);

IF AList.First=NIL THEN

BEGIN

AList.First^.item:=NullItem;

AList.First^.Next:=Temp

END

ELSE

IF PrevNodeP<>NIL THEN

BEGIN

Temp^.Next:=PrevNodeP^.Next;

PrevNodeP^.Next:=Temp;

END;

END;


Capitolo 17

AListFirst

PrevNodeP

NullItem

Item

Item

Item

Next

Next

Next

Next

  • Pseudo codice per cancellare un nodo

  • Controllare se la lista è vuota.

  • Controllare che non si cerchi di cancellare un puntatore che vale NIL.

  • Cancellare il nodo indicato dal puntatore, noto, del nodo che lo precede, e far puntare quest’ultimo sul nodo succesivo a quello da cancellare.


Capitolo 17

Controllare che non si cerchi di cancellare un puntatore preceduto da NIL

Caso in cui il nodo da cancellare è il primo

Controllare se la lista è vuota

Cancella il nodo puntato da PrevNodeP e punta PrevNodeP sul successore del nodo da eliminare

PROCEDURE DeleteNode(PrevNodeP:LNodeP;VAR AList:ListType);

{Cancella ilNodo che nella lista segue quello puntato da PrevNodeP . Se PrevNodeP è NIL, viene cancellato il primo nodo. Se la lista è vuota non succede nulla }

PROCEDURE DeleteNode(PrevNodeP:LNodeP;VAR AList:ListType);

VAR

Temp:LNodeP;

BEGIN

IF EmptyList(Alist)=FALSE THEN

IF PrevNodeP<>NIL THEN

IF PrevNodeP^.Next<>NIL THEN

BEGIN

Temp:=PrevNodeP^.Next;

END;

IF PrevNodeP=AList.First THEN

BEGIN

writeln(' PrevNP = AlistFirst ');

Temp:=AList.First;

AList.First:=AList.First^.Next;

END

ELSE

PrevNodeP^.Next:=PrevNodeP^.Next^.Next;

KillNode(Temp)

END;


Capitolo 17

Introduciamo due funzioni che permettono la gestione delle liste invece che attraverso i puntatori, attraverso la posizione dei singoli nodi nella lista.

FUNCTION Seleziona(AList:ListType;Index:integer):ItemType;

{Data una lista resituisce l'Item che si trova nella posizione Index}

BEGIN

IF Index<=0 THEN Seleziona:=NullItem

ELSE

Seleziona:=Ennesimo(AList.First^.Next,Index)

END;

CONST

NullItem= ' ' TYPE

ItemType= STRING[20]

LNodeP=^LNodeType

LNodeType = RECORD

Item:ItemType;

Next:LNodeP

END;

ListType = RECORD

First:LNodeP

END;

VAR

AList:ListType;

FUNCTION Ennesimo(P:LNodeP;n:integer):ItemType;

{ricorsivamente cerca l'ennesimo elemento della lista}

VAR

AnItem:ItemType;

BEGIN

IF n=1 THEN

BEGIN

ItemValue(P,AnItem);

Ennesimo:=AnItem;

END

ELSE

Ennesimo:= Ennesimo(NextNode(P),n-1) {funzione ricorsiva}

END;


Capitolo 17

Introduciamo una funzione che permette la ricerca del puntatore che precede un preassegnato puntatore.

FUNCTION CercaPrevP(Px:LNodeP; Plist:LnodeP; VAR AList:ListType):LNodeP;

VAR

CandP,Temp:LNodeP;

BEGIN

IF FirstNode(Alist)=Px THEN

CercaPrevP:=AList.First

ELSE

BEGIN

CandP:=FirstNode(Alist);

WHILE (CandP <> Px) AND (CandP<>NIL) DO

BEGIN

Temp:=CandP;

CandP:=CandP^.Next

END;

CercaPrevP:=Temp

END

END;


Capitolo 17

Introduciamo una funzione che permette la ricerca del puntatore di un nodo di cui è noto l’item.

FUNCTION LPos(List:Listtype; SearchItem:ItemType):LNodeP;

VAR

CandNode: LNodeP;

CandItem:ItemType;

BEGIN

CandNode:=FirstNode(List); {il primo item nella lista o NIL}

ItemValue(CandNode,CandItem);

WHILE (CandItem <> NullItem) AND (CandItem <> SearchItem) DO

BEGIN

CandNode:=NextNode(CandNode);

ItemValue (CandNode,CandItem);

END;

IF CandItem=SearchItem THEN

Lpos:=CandNode

ELSE

Lpos:=NIL ;

END;


Capitolo 17

PROCEDURE ShowList(Px:LNodeP);

VAR

AName:ItemType;

BEGIN

ItemValue(Px,AName);

WHILE Px <> NIL DO

BEGIN

writeln(AName);

Px:=NextNode(Px);

ItemValue(Px, AName)

END

END;


Capitolo 17

PROGRAM TestListe;

USES UList00;

VAR

Lista:ListType;

Nome,Nome2:ItemType;

Indice:integer;

Nodo,Nodo1, Px,PrevPx:LNodeP;

PROCEDURE CaricaLista(VAR Lista:ListType);

BEGIN

writeln(' CREA LISTA');

MakeList(Lista);

writeln;

Nodo1:=Lista.First;

writeln(' Dammi un nome');

readln(Nome);

WHILE Nome<> NullItem DO

BEGIN

InsertNode(Nome,Nodo1,Lista);

Nodo1:=NextNode(Nodo1);

writeln(' Dammi un nome');

readln(Nome);

END;

writeln('Lista iniziale');

ShowList(FirstNode(Lista));

END;


Capitolo 17

PROCEDURE CancellaNodo(VAR Lista:ListType);

BEGIN

writeln(' Quale nome vuoi cancellare ');

readln(Nome);

writeln;

Px:=Lpos(Lista,Nome);

PrevPx:=CercaPrevP(Px,Lista);

DeleteNode(PrevPx,Lista);

writeln('Lista dopo la cancellazione');

ShowList(FirstNode(Lista));

readln;

END;

PROCEDURE InserisciNodo(VAR Lista:ListType);

BEGIN

writeln('Inserisci un nodo dopo l''item ');

readln(Nome);

writeln('Nuovo nodo ');

readln(Nome2);

IF Nome='0' THEN Nodo1:=Lista.First

ELSE Nodo1:=Lpos(Lista,Nome);

InsertNode(Nome2,Nodo1,Lista);

writeln('Lista dopo inserimento di un nodo');

ShowList(FirstNode(Lista));

readln

END;


Capitolo 17

PROCEDURE CancellaNumero(VAR Lista:ListType);

BEGIN

writeln('Cancella il nodo n. ');

readln(Indice);

Nome:=Seleziona(Lista,Indice);

Px:=Lpos(Lista,Nome);

PrevPx:=CercaPrevP(Px,Lista);

DeleteNode(PrevPx,Lista);

writeln('Lista dopo la cancellazione del nodo n. ',Indice);

ShowList(FirstNode(Lista));

readln

END;

{****************** BODY *****************}

BEGIN

CaricaLista(Lista);

CancellaNodo(Lista);

InserisciNodo(Lista);

CancellaNumero(Lista)

END.


Capitolo 17

Deve avere almeno un campo per i dati e un campo per il link

Deve avere almeno un campo che punta a un nodo

Consigli per un corretto uso dei puntatori e ADT

Un errore derivante da un cattivo uso di puntatori è difficilmente rilevabile.

Una ADT deve essere tale da non permettere mai all’utente di poter dereferenziare una variabile puntatore. Quindi l’utente non deve mai avere a che fare con operazioni che implicano direttamente la gestione dei puntatori.

I puntatori sono utili perché permettono la gestione di variabili dinamiche con conseguente risparmio di memoria e possono puntare direttamente a qualunque tipo di variabili incluse le variabili puntatore stesse.

Quando si progettano ADT che usano link bisogna definire due data type:

- variabile nodoes. LNodeType

- struttura dati nel suo complessoes. QType


Capitolo 17

Per progettare una ADT bisogna costruire due insiemi di operazioni:

Il primo deve avere

a - costruttori per creare o eliminare nodi

b - selettori per accedere alle singole variabili contenute nei campi del nodo

Il primo deve avere tutte le operazioni tipiche della applicazione cui fa riferimento

es. MakeStack, ShowOList, ….

Usare una chiamata per valore quando si vuole dereferenziare un puntatore.

Quando si deve aggiungere o eliminare un nodo si passa il nodo per valore e la struttura per VAR

Se si vuole assegnare un nuovo valore (indirizzo) ad una variabile puntatore allora bisogna fare una chiamata per VAR.

La memoria riservata alle variabili non è mai allocata o deallocata da istruzioni di assegnazione ma solo attraverso le procedure new e dispose.

Usare dispose non appena siamo sicuri che le variabili non sono più utilizzate.

Non è possibile dereferenziare un puntatore che punta a NIL. In caso contrario si ha errore.


Capitolo 17

Gli operatori che si possono applicare a NIL sono solo = o <>. Non funzionanno > o <.

  • Nel progetto di ADT di liste legate bisogna sempre avere una procedura di

  • creazione della struttura e di controllo se essa è vuota;

  • cancellazione di nodi della struttura con controllo se essa è vuota;

Algoritmo per aggiungere nodi

assegna i valori ai campi del nodo da aggiungere

assegna i link dal nodo da aggiungere alla struttura

assegna i link dalla struttura al nodo da aggiungere

Algoritmo per eliminare nodi

assegna i valori dei link per bypassare il nodo da eliminare

dispose il nodo da eliminare

Scrivere sempre una procedura per mostrare i valori delle variabili contenute nei campi delle strutture utilizzate.


Capitolo 17

  • Esercizio

  • Creare una lista legata lineare di interi in maniera casuale.

  • Usando la ADTL introdotta a lezione:

  • cercare il numero più grande e metterlo in coda alla lista

  • eliminare tutti i numeri presenti più di una volta


Capitolo 17

FINE


Capitolo 17

PROCEDURE MakeList(VAR AList:ListType);

crea una lista vuota

PROCEDURE InsertNode(AnItem:ItemType;PrevNodeP:LNodeP;VARLastNodeP:LNodeP; VAR AList:ListType);

inserisce il nodo AnItem in una lista subito dopo un altro nodo identificato tramite il suo puntatore PrevNodeP e fornisce il puntatore del nuovo nodo inserito LastNodeP

PROCEDURE DeleteNode(PrevNodeP:LNodeP;VAR AList:ListType);

elimina un nodo in una lista subito dopo un altro nodo identificato tramite il suo puntatore PrevNodeP

FUNCTION CercaPrevP(Px:LNodeP; Plist:LnodeP; VAR AList:ListType):LNodeP;

dato il puntatore di un nodo Px fornisce il valore del puntatore del nodo che lo precede

FUNCTION FirstNode(VAR AList:ListType):LNodeP;

ritorna il puntatore al primo nodo della lista

FUNCTION EmptyList(AList:ListType):boolean;

controlla se una lista è vuota

FUNCTION LPos(List:Listtype; SearchItem:ItemType):LNodeP;

Fornisce il puntatore di un preassegnato nodo SearchItem

FUNCTION Seleziona(AList:ListType;Index:integer):ItemType;

Fornisce il nome del nodo che si trova al posto Index


Capitolo 17

NullItem

Item

Item

Item

Item

Item

Next

Next

Next

Next

Next

Next

AListFirst

PrevNodeP

AListFirst

PrevNodeP


  • Login