Scaricare la presentazione
La presentazione è in caricamento. Aspetta per favore
PubblicatoEula Pavone Modificato 11 anni fa
2
ESERCIZIO Date le seguenti definizioni TYPE nodoint=^tipoint tipoint=RECORD numero:integer; link:nodoint; END; ListaInt:Nodoint; Siano date 2 liste una Lint:ListaInt e una Lchar:ListaChar. Sia data la funzione trovato(Lchar,intero):char e la procedura sostituisci(intero,Lint,trovato) Scrivere un algoritmo che sostituisca ogni elemento della lista Lint con il codice ASCII del carattere trovato in Lchar nella posizione determinata dal valore dellelemento in Lint. Esempio Input: Lint: 5 4 3Lchar: a f g h m Output Lint 109 104 103 Nota: La funzione Trovato restituisce il carattere 0 nel caso in cui il valore intero supera la lunghezza di Lchar. Tale carattere può essere sostituito allintero. nodochar=^tipochar tipochar=RECORD carattere:char; link:nodochar; END; ListaChar:=Nodochar;
3
GLI ALBERI COME STRUTTURE DATI Search Tree - (Albero di ricerca) - Memorizza informazioni in maniera tale che possano essere ritrovate molto velocemente e le operazioni di inserimento e cancellazione nodi sono molto efficienti.
4
ALBERI BINARI Un albero è binario se ogni nodo è al più collegato ad altri due Un albero binario è: –Lalbero vuoto –oppure è costituito da una radice e da un sottoalbero sinistro ed un sottoalbero destro Lalbero è dunque una struttura ricorsiva non lineare. I suoi elementi sono detti nodi
5
I due disegni rappresentano due alberi uguali ma due alberi binari diversi. Lovvio modo di rappresentare un albero consiste nellassegnare ad ogni nodo due puntatori uno che punta al sottoalbero sinistro ed uno che punta al sottoalbero destro.
6
Per gestire gli alberi introduciamo un ADT costituito da nodi non più con uno ma con due campi per i puntatori. Attraverso questa struttura potremo rappresentare gli alberi di ricerca binari. Albero Binario Radice (root) Sotto albero
7
Carlo Maria PeppeNicola Anna Emma Giulio CarlaGuido Ugo Angela
8
Definiamo sotto albero ogni nodo in cui almeno un puntatore non è uguale a NIL ma punta ad un altro nodo o sotto albero. Definiamo radice di un sotto albero quel nodo che punta ad almeno un altro nodo (NB Negli alberi binari si può al massimo puntare a due nodi (destro e sinistro). La variabile dinamica albero può essere definita attraverso la sua radice, il nodo a partire dal quale si possono raggiungere tutti gli altri nodi della struttura. XXX Tree Left StructureRight Structure Un albero (sotto albero), che punta a NIL e cioè non contiene nodi è detto albero (sotto albero) vuoto.
9
Albero Binario Radice (root) Sotto albero Cammino (path) X Genitore Figlio Livello del nodo X = 3 Nodi fratelli Altezza dellalbero= Massimo numero di livelli H=3 Foglie
10
Un albero binario è ordinato quando il campo chiave di ogni nodo è minore del campo chiave di ogni nodo del suo sottoalbero destro ed è maggiore del campo chiave di ogni nodo del suo sottoalbero sinistro. Si parla in questo caso anche di binary search tree (BST).
11
Sergio Toni LuigiUgo Anna Dora Giulio RiccardoGuido Maria Roberto Un albero binario di ricerca (BST) è tale se: - le foglie sinistre hanno un valore del campo chiave inferiore del nodo padre - le foglie destre hanno un valore del campo chiave maggiore del nodo padre Campo chiave Key Field LeftRight
12
CONST NullKey= un simbolo o valore per indicare NIL ' ; NullInfo=quando possibile assegna un significato al nodo NIL TYPE KItemType= STRING[20] InfoType= un data type per le informazioni non key BSTP=^BSTNode{puntatore a un nodo} BSTNode = RECORD Key:KItemType; Info: InfoType; Left, Right: BSTP END; LeftKeyInfoRight TNode
13
Le operazioni che ci interessa definire sono: creazione di un nuovo nodo con un valore assegnato ai campi dati (Key e Info) e NIL ai campi link (Left e Right) dispose (dealloca) di un nodo supposto che esso esista come variabile dinamica selezionare un nodo data una chiave selezionare le Info collegate al nodo seleziona il figlio a sinistra di un dato nodo seleziona il figlio a destra di un dato nodo LeftKeyInfoRight TNode
14
INTERFACE PROCEDURE MakeTNode(KeyValue:KItemType; TheInfo:InfoType; VAR TNode:BSTP); { Crea un nuovo nodo, assegnando a KeyValue e TheInfo un valore e il valore NIL per i campi Left e Right } PROCEDURE KillTNode(VAR Node:LNodeP); {dispose la memoria allocata per il TNode e poi pone il TNode a NIL. } PROCEDURE GetNodesKey(TNode:BSTP; VAR TheKey:KItemType); {ritorna il key field del nodo puntato da Tnode, se Tnode è NIL allora ritorna il valore di NullKey} PROCEDURE GetNodesInfo(TNode:BSTP; VAR TheInfo:InfoType); {ritorna le informazioni del nodo puntato da Tnode, se Tnode è NIL allora ritorna il valore di NullInfo} CONST NullKey= un simbolo o valore per indicare NIL ' ; NullInfo=quando possibile assegna un significato al nodo NIL TYPE KItemType= STRING[20] InfoType= un data type per le informazioni non key BSTP=^BSTNode{puntatore a un nodo} BSTNode = RECORD Key:KItemType; Info: InfoType; Left, Right: BSTP END; LeftKeyInfoRight TNode
15
FUNCTION NodesLeftTree(TNode:BSTP) : BSTP; {ritorna il puntatore al sotto albero sinistro di Tnode. Se T Node è NIL allora ritorna NIL } CONST NullKey= un simbolo o valore per indicare NIL ' ; NullInfo=quando possibile assegna un significato al nodo NIL TYPE KItemType= STRING[20] InfoType= un data type per le informazioni non key BSTP=^BSTNode{puntatore a un nodo} BSTNode = RECORD Key:KItemType; Info: InfoType; Left, Right: BSTP END; FUNCTION NodesRightTree(TNode:BSTP) : BSTP; {ritorna il puntatore al sotto albero destro di Tnode. Se T Node è NIL allora ritorna NIL } LeftKeyInfoRight TNode
16
PROCEDURE MakeTNode(KeyValue:KItemType; TheInfo:InfoType; VAR TNode:BSTP); { Crea un nuovo nodo, assegnando a KeyValue e TheInfo un valore e il valore NIL per i campi Left e Right } BEGIN new(Tnode); WITH TNode^ DO BEGIN Key:=KeyValue; Info:=TheInfo; Left:=NIL; Right:=NIL END END; CONST NullKey= un simbolo o valore per indicare NIL ' ; NullInfo=quando possibile assegna un significato al nodo NIL TYPE KItemType= STRING[20] InfoType= un data type per le informazioni non key BSTP=^BSTNode{puntatore a un nodo} BSTNode = RECORD Key:KItemType; Info: InfoType; Left, Right: BSTP END; LeftKeyInfoRight TNode
17
PROCEDURE KillTNode(VAR Node:LNodeP); {dispose la memoria allocata per il TNode e poi pone il TNode a NIL. } BEGIN IF Tnode <> NIL THEN BEGIN dispose(TNode); Tnode:=NIL END END; CONST NullKey= un simbolo o valore per indicare NIL ' ; NullInfo=quando possibile assegna un significato al nodo NIL TYPE KItemType= STRING[20] InfoType= un data type per le informazioni non key BSTP=^BSTNode{puntatore a un nodo} BSTNode = RECORD Key:KItemType; Info: InfoType; Left, Right: BSTP END; LeftKeyInfoRight TNode
18
PROCEDURE GetNodesKey(TNode:BSTP; VAR TheKey:KItemType); {ritorna il key field del nodo puntato da Tnode, se Tnode è NIL allora ritorna il valore di NullKey} BEGIN IF TNode <> NIL THEN TheKey:= TNode ^.Key ELSE TheKey:= NullKey END; CONST NullKey= un simbolo o valore per indicare NIL ' ; NullInfo=quando possibile assegna un significato al nodo NIL TYPE KItemType= STRING[20] InfoType= un data type per le informazioni non key BSTP=^BSTNode{puntatore a un nodo} BSTNode = RECORD Key:KItemType; Info: InfoType; Left, Right: BSTP END; LeftKeyInfoRight TNode
19
PROCEDURE GetNodesInfo(TNode:BSTP; VAR TheInfo:InfoType); {ritorna le informazioni del nodo puntato da Tnode, se Tnode è NIL allora ritorna il valore di NullInfo} BEGIN IF TNode <> NIL THEN TheInfo:= TNode ^.Info ELSE TheKey:= NullInfo END; CONST NullKey= un simbolo o valore per indicare NIL ' ; NullInfo=quando possibile assegna un significato al nodo NIL TYPE KItemType= STRING[20] InfoType= un data type per le informazioni non key BSTP=^BSTNode{puntatore a un nodo} BSTNode = RECORD Key:KItemType; Info: InfoType; Left, Right: BSTP END; LeftKeyInfoRight TNode
20
FUNCTION NodesLeftTree(TNode:BSTP) : BSTP; {ritorna il puntatore al sotto albero sinistro di Tnode. Se T Node è NIL allora ritorna NIL } BEGIN IF Tnode <> NIL THEN NodesLeftTree:=Tnode^Left ELSE NodesLeftTree:=NIL END: CONST NullKey= un simbolo o valore per indicare NIL ' ; NullInfo=quando possibile assegna un significato al nodo NIL TYPE KItemType= STRING[20] InfoType= un data type per le informazioni non key BSTP=^BSTNode{puntatore a un nodo} BSTNode = RECORD Key:KItemType; Info: InfoType; Left, Right: BSTP END; LeftKeyInfoRight TNode
21
FUNCTION NodesRightTree(TNode:BSTP) : BSTP; {ritorna il puntatore al sotto albero destro di Tnode. Se T Node è NIL allora ritorna NIL } BEGIN IF Tnode <> NIL THEN NodesRightTree:=Tnode^. Right ELSE NodesRightTree:=NIL END: CONST NullKey= un simbolo o valore per indicare NIL ' ; NullInfo=quando possibile assegna un significato al nodo NIL TYPE KItemType= STRING[20] InfoType= un data type per le informazioni non key BSTP=^BSTNode{puntatore a un nodo} BSTNode = RECORD Key:KItemType; Info: InfoType; Left, Right: BSTP END; LeftKeyInfoRight TNode
22
Pseudo codice per un algoritmo generalizzato di selezione nodi PROCEDURE GetNodeField(ANode:NodeP; VAR FieldVar: FieldType) IF ANode <> NIL THEN FieldVar ANode^.identificatore della variabile di campo selezionata ELSE FieldVar NullValue
23
Ugo Toni Maria Anna Dora SergioGiulio Guido Luigi Le stesse informazioni possono essere contenute in alberi binari di forma diversa. Anna Dora Sergio Giulio Luigi Guido RiccardoMaria Riccardo Toni Ugo
24
Un albero si dice bilanciato se il livello di tutte le foglie è uguale allaltezza dellalbero o a questa stessa altezza meno 1. H=3 L=3 Foglie H=3 L=3 L=2
25
Foglie H=5 L=3 L=2 L=4 L=5
26
In un albero bilanciato il tempo massimo di ricerca è di O(log 2 (N)) dove N è il numero di nodi. E evidente che un albero bilanciato si esplora per fare una ricerca in un numero di passi inferiore a quello necessario per esplorare un albero non bilanciato. Se un albero bilanciato ha M livelli, il numero di nodi di cui è formato può variare tra 2 M e 2 (M+1) -1.
27
0 1 M ALBERO BILANCIATO CON 3 LIVELLI N° NODI Totale Nodi N° NODI
28
ALBERO BILANCIATO CON 3 LIVELLI Totale Nodi N° NODI N° NODI 0 1 M Totale Nodi
29
Serie geometrica
30
Supponiamo sia assegnata una lista di N oggetti tra i quali esiste una relazione dordine. Se riusciamo a inserire questi oggetti in un albero di ricerca bilanciato allora il numero di passi per trovare un qualunque oggetto è limitato da O(log 2 (N)). Se questo non avviene il caso peggiore in cui possiamo trovarci è pari a O(N). Si può dimostrare che un albero di ricerca binario costruito in maniera casuale, quindi non necessariamente bilanciato, effettua in media un numero di passi per effettuare la ricerca pari a 1.39* O(log 2 (N)). Toni Maria Ugo Riccardo Anna Dora Sergio Giulio Luigi Guido
31
ESEMPIO Supponiamo di avere un albero di tipo BST, chiamiamo con Root il primo nodo. Scrivere una funzione LeftMost che fornisca il puntatore del nodo più a sinistra che si incontra a partire da Root. Sergio Toni Anna Dora Giulio RiccardoGuido Maria Roberto LeftKeyInfoRight TNode CONST NullKey= un simbolo o valore per indicare NIL ' ; NullInfo=quando possibile assegna un significato al nodo NIL TYPE KItemType= STRING[20] InfoType= un data type per le informazioni non key BSTP=^BSTNode{puntatore a un nodo} BSTNode = RECORD Key:KItemType; Info: InfoType; Left, Right: BSTP END;
32
LeftKeyInfoRight TNode CONST NullKey= un simbolo o valore per indicare NIL ' ; NullInfo=quando possibile assegna un significato al nodo NIL TYPE KItemType= STRING[20] InfoType= un data type per le informazioni non key BSTP=^BSTNode{puntatore a un nodo} BSTNode = RECORD Key:KItemType; Info: InfoType; Left, Right: BSTP END; FUNCTION LeftMost(Root: BSTP): BSTP; VAR NodoEsaminato:BSTP; BEGIN IF EmptyTree(Root) THEN NodoEsaminato = NIL; ELSE NodoEsaminato = Root; WHILE NodesLeftTree(NodoEsaminato) <> NIL DO NodoEsaminato = NodesLeftTree(NodoEsaminato) ; LeftMost: = NodoEsaminato END: Definizione della funzione Definizione delle variabili Verifica se lalbero è vuoto Cerca il nodo
33
OPERAZIONI SUI BST Ogni nodo di un BST punta ad altri due nodi, ciascuno dei quali può essere visto come una variabile dinamica di tipo record. Quindi una variabile di tipo BSTType, cioè un puntatore alla radice di un BST, che è a sua volta una variabile BST, può essere passata da un blocco ad un altro. In altre parole dato un nodo di un BST, questo è radice per i suoi sottoalberi e i nodi a cui punta sono a loro volta radici di altri sottoalberi. Quindi possiamo adoperare ricorsivamente queste variabili. Poiché una variabile BST può essere interpretata o come nodo di un BST o come un sotto albero di un BST, pur essendo variabili dello stesso tipo parleremo nel primo caso di un tipo BSTP (puntatore a un nodo) e nel secondo caso di un tipo BSTType (puntatore a un albero) CONST NullKey= un simbolo o valore per indicare NIL ' ; NullInfo=quando possibile assegna un significato al nodo NIL TYPE KItemType= STRING[20] InfoType= un data type per le informazioni non key BSTP=^BSTNode{puntatore a un nodo} BSTNode = RECORD Key:KItemType; Info: InfoType; Left, Right: BSTP END; BSTType=BSTP VAR NomeAlbero:BSTType LeftKeyInfoRight TNode
34
INTERFACE PROCEDURE MakeTree(VAR Tree: BSTType); {inizializza a NIL lalbero, creando un albero vuoto} PROCEDURE AddTNode(KeyValue:KItemType; TheInfo:InfoType;VAR Tree: BSTType; VAR Done:boolean); {aggiunge un nodo allalbero rispettando la struttura di un BST, se il KeyValue è già presente nellalbero non fa nulla e Done risulta False} PROCEDURE DeleteTNode(KeyValue:KItemType;VAR Tree: BSTType; VAR Done:boolean); {elimina il nodo con chiave KeyValue, se esso non esiste Done risulta False} FUNCTION SearchTNode(Tree: BSTType; KeyValue:KItemType): BSTP; {cerca il nodo con chiave KeyValue, se esso non esiste ritorna NIL} FUNCTION EmptyTree(Tree: BSTType): boolean; {ritorna vero se lalbero è vuoto}
35
ESEMPIO: COSTRUZIONE DI UN BST DI NOMI LeftKeyInfoRight TNode CONST NullKey= ' ; NullInfo= TYPE KItemType= STRING[20] InfoType= STRING[20] BSTP=^BSTNode{puntatore a un nodo} BSTNode = RECORD {variabile dinamica per un nodo} Key:KItemType; Info: InfoType; Left, {radice del sottoalbero di sinistra} Right: BSTP {radice del sottoalbero di destra} END; BSTType=BSTP; {definizione per la variabile albero} VAR NameTree:BSTType;
36
COSTRUZIONE DI UN BST DI NOMI Sergio Toni Anna Dora Giulio RiccardoGuido Maria Roberto Maria Giulio Sergio Dora Guido Riccardo Toni Anna Roberto return Supponiamo che vengano introdotti da tastiera i seguenti nomi:
37
Pseudo codice MakeTree(NameTree) introduci Nome WHILE Nome <> NullKey DO AddTNode(Nome, NullInfo, NameTree, Success) IF NOT Success THEN segnala che il Nome esiste già introduci il nome mostra il messaggio di fine lavoro
38
CONST NullKey= ' ; NullInfo= TYPE KItemType= STRING[20] InfoType= STRING[20] BSTP=^BSTNode BSTNode = RECORD Key:KItemType; Info: InfoType; Left, Right: BSTP END; BSTType=BSTP; VAR NameTree:BSTTYpe; PROCEDURE BuildNameTree(VAR NameTree: BSTType); {costruisce un albero a cui assegna un Nome dato in input} VAR Nome:KItemType; Success: boolean; BEGIN MakeTree(NameTree); write( Dammi un nome : ); readln(Nome); WHILE Nome <> NullKey DO BEGIN AddTNode(Nome, NullInfo, NameTree, Success); IF NOT Success THEN writeln( Nome, esiste già); write( Dammi un nome : ); readln(Nome) END; writeln( Lalbero è stato piantato); END;
39
DEFINIZIONE DI ATTRAVERSAMENTO DI UN BST Visitare tutti i nodi di un BST di nomi, a partire dalla radice, e elencare i nomi in ordine alfabetico. Anna Dora Giulio Guido Maria Riccardo Roberto Sergio Toni Sergio Toni Anna Dora Giulio RiccardoGuido Maria Roberto
40
MOSTRA IL CONTENUTO DI UN BST Mostra le Chiavi (KeyItem) di tutti i nodi del sottoalbero sinistro di NameTree Mostra la Chiave (KeyItem) della radice di NameTree Mostra le Chiavi (KeyItem) di tutti i nodi del sottoalbero destro di NameTree Sergio Toni Anna Dora Giulio RiccardoGuido Maria Roberto ShowTree(NodesLeftTree(NameTree)); GetNodesKey(NameTree, Nome); Writeln(Nome) ShowTree(NodesRightTree(NameTree)); Pseudo codice
41
La procedura ShowTree(NameTree) è una procedura ricorsiva il cui case base è rappresentato dallalbero vuoto (EmptyTree). In altre parole il processo di pop inizia non appena largomento di ShowTree(NameTree) è un albero vuoto. PROCEDURE ShowTree(NameTree: BSTType); VAR NodesKey: KItemType; BEGIN IF NOT EmptyTree(NameTree) THEN BEGIN ShowTree(NodesLeftTree(NameTree)); GetNodesKey(NameTree, Nome); writeln(Nome) ShowTree(NodesRightTree(NameTree)); END END;
42
IMPLEMENTATION PROCEDURE MakeTree(VAR Tree: BSTType); {inizializza a NIL lalbero, creando un albero vuoto} BEGIN Tree:=NIL END; FUNCTION EmptyTree(Tree: BSTType): boolean; {ritorna vero se lalbero è vuoto} BEGIN EmptyTree:=Tree=NIL END;
43
RICERCA DI UN DATO SU UN BST Sergio Toni Anna Dora Giulio RiccardoGuido Maria Roberto Riccardo ?????????
44
FUNCTION Binary (VAR Studenti: StudenteRecord; MatrCercata:StringaNome; Lo, Hi :integer) :integer VAR Mid:integer; BEGIN IF Lo>Hi THEN Binary := 0 ELSE BEGIN Mid (Lo+Hi) DIV 2 IF Studenti[Mid].Matr=MatrCercata THEN Binary := Mid ELSE IF Studenti[Mid].Matr<MatrCercata THEN Binary := Binary(Studenti, MatrCercata, Mid+1, Hi) ELSE Binary := Binary(Studenti, MatrCercata, Lo, Mid-1) END; CASE BASE 2 ESPRESSIONE RICORSIVA CASE BASE 1
45
Pseudo codice FUNCTION SearchTNode(Tree; KeyValue); BSTP IF EmptyTree(Tree) THEN SearchTNode NIL ELSE GetNodesKey(Tree, TheKey) IF TheKey = KeyValue THEN SearchTNode Tree ELSE IF KeyValue < TheKey SearchTNode SearchTNode(NodesLeftTree(Tree), KeyValue) ELSE SearchTNode SearchTNode(NodesRightTree(Tree), KeyValue)
46
FUNCTION SearchTNode(Tree: BSTType; KeyValue:KItemType): BSTP; {cerca il nodo con chiave KeyValue, se esso non esiste ritorna NIL} VAR TheKey: KItemType; BEGIN IF EmptyTree(Tree) THEN SearchTNode NIL ELSE BEGIN GetNodesKey(Tree, TheKey) IF TheKey = KeyValue THEN SearchTNode Tree ELSE IF KeyValue < TheKey SearchTNode SearchTNode(NodesLeftTree(Tree), KeyValue) ELSE SearchTNode SearchTNode(NodesRightTree(Tree), KeyValue) END END;
47
ESERCIZIO Sia assegnato un albero binario. scrivere un algoritmo tale che sposti ogni figlio sinistro nel corrispondente figlio destro e viceversa. A BC DEF GH A CB DFE HG
48
AGGIUNTA DI UN DATO SU UN BST Sergio Toni Anna Dora Giulio RiccardoGuido Maria Roberto Rolando Per aggiungere un nodo a un BST è necessario innanzitutto verificare che lItem non esiste già, perché in tal caso il nodo non viene aggiunto. Se non esiste bisogna trovare la sua corretta posizione nellalbero, cioè il suo genitore e attribuirgli come figli, sinistro e destro il puntatore NIL.
49
PROCEDURE AddTNode(KeyValue:KItemType; TheInfo:InfoType;VAR Tree: BSTType; VAR Done:boolean); {aggiunge una foglia allalbero rispettando la struttura di un BST, se il KeyValue è già presente nellalbero non fa nulla e Done risulta False} PROCEDURE DeleteTNode(KeyValue:KItemType;VAR Tree: BSTType; VAR Done:boolean); {elimina il nodo con chiave KeyValue ricostruendo la struttura BST. Se il Nodo non esiste Done risulta False}
50
Pseudo Codice di AddTNode Search(Tree, KeyValue, TNode, Parent) IF NOT EmptyTree(TNode) THEN Done FALSE ELSE crea e aggiungi un nuovo nodo come figlio del nodo Parent Done TRUE Se il nodo che vogliamo inserire, avente un certo KeyValue, esiste, allora Tnode non è vuoto e quindi non lo aggiungiamo altrimenti lo aggiungiamo
51
PROCEDURE AddTNode(KeyValue:KItemType; TheInfo:InfoType;VAR Tree: BSTType; VAR Done: boolean); VAR Tnode, Parent : BSTP; {deve valere NIL se il nodo esiste già} ParentsKey: KeyItemType;{genitore del nodo da aggiungere} BEGIN Search(Tree, KeyValue, TNode, Parent) IF NOT EmptyTree(TNode) THEN{il nodo esiste già} Done := FALSE ELSE {crea e aggiungi un nuovo nodo come figlio del nodo Parent} BEGIN IF EmptyTree(Parent) THEN{il nuovo nodo sarà la radice} MakeTNode(KeyValue, TheInfo, Tree) ELSE BEGIN GetNodesKey(Parent, ParentsKey); IF ParentsKey > KeyValue THEN {il nuovo nodo va a sinistra} MakeTNode(KeyValue, TheInfo, Parent^.Left) ELSE {il nuovo nodo va a destra} MakeTNode(KeyValue, TheInfo, Parent^.Right) END; Done := TRUE END END; PROCEDURE MakeTNode(KeyValue:KItemType; TheInfo:InfoType; VAR TNode:BSTP); { Crea un nuovo nodo, assegnando a KeyValue e TheInfo un valore e il valore NIL per i campi Left e Right }
52
Search Search(Tree, KeyValue, TNode, Parent) Obiettivo: cercare un cammino verso un determinato nodo dellalbero. Se il nodo non esiste ritorna NIL. Se esiste ritorna il puntatore al nodo individuato. Pseudo Codice Parent NIL {la root non ha genitori} TNode Tree {la radice è il primo nodo esaminato} GetNodesKey(TNode, NodesKey){estrai la chiave del nodo in esame} WHILE ci sono altri nodi da esaminare AND non si è ancora trovato il nodo DO Parent TNode Tnode il sottoalbero legato al KeyValue GetNodesKey(TNode, NodesKey){estrai la chiave del nodo in esame} EmptyTree(TNode) NodesKey <> KeyValue IF NodesKey > KeyValue THEN TNode radice del sottoalbero sinistro ELSE TNode radice del sottoalbero destro Il padre dellultimo nodo esaminato durante la ricerca di KeyValue
53
19 1321 1215 1418 16 17 20 24 23 26 Aggiungi 18 Tnode NIL Pseudo Codice Parent NIL {la root non ha genitori} TNode Tree {la radice è il primo nodo esaminato} GetNodesKey(TNode, NodesKey){estrai la chiave del nodo in esame} WHILE ci sono altri nodi da esaminare AND non si è ancora trovato il nodo DO Parent TNode Tnode il sottoalbero legato al KeyValue GetNodesKey(TNode, NodesKey){estrai la chiave del nodo in esame} Aggiungi 22 22 Tnode = NIL BEGIN Search(Tree, KeyValue, TNode, Parent) IF NOT EmptyTree(TNode) THEN{il nodo esiste già} Done := FALSE ELSE {crea e aggiungi un nuovo nodo come figlio del nodo Parent} BEGIN IF EmptyTree(Parent) THEN MakeTNode(KeyValue, TheInfo, Tree) {il nuovo nodo sarà la radice} ELSE BEGIN GetNodesKey(Parent, ParentsKey); IF ParentsKey > KeyValue THEN {il nuovo nodo va a sinistra} MakeTNode(KeyValue, TheInfo, Parent^.Left) ELSE {il nuovo nodo va a destra} MakeTNode(KeyValue, TheInfo, Parent^.Right) END; Done := TRUE END END; AddTNode Search
54
PROCEDURE Search(Tree: BSTT, KeyValue: KItemType, VAR TNode, Parent: BSTP); VAR NodesKey: KItemType; BEGIN Parent:= NIL {la root non ha genitori} Tnode:= Tree {la radice è il primo nodo esaminato} GetNodesKey(TNode, NodesKey){estrai la chiave del primo nodo} WHILE NOT EmptyTree(TNode) AND (NodesKey <> KeyValue) DO BEGIN Parent:= Tnode IF NodesKey > KeyValue THEN Tnode:= NodesLeftTree(TNode) ELSE Tnode:= NodesRightTree(TNode) GetNodesKey(TNode, NodesKey){estrai la chiave del nodo in esame} END END; Ricordarsi che GetNodesKey nel caso trovi NIL ritorna NullKey
55
Problema Realizzare una procedura che elimina il nodo con chiave KeyValue Pseudo Codice Search(Tree, KeyValue, Candidate, Parent) GetNodesKey(Candidate, CandsKey) IF CandsKey <> KeyValue THEN Done FALSE ELSE riorganizza lalbero dopo aver rimosso Candidate KillTNode(Candidate) Done TRUE Ritorna la chiave CandsKey puntata da Candidate Implica che se cerco di nuovo un nodo con chiave CandsKey non lo trovo e che lalbero che resta, deallocando il nodo Candidate, è ancora un BST
56
Analizziamo il problema della riorganizzazione dellalbero una volta eliminato un nodo. Caso a- il nodo da eliminare ha il sotto albero sinistro vuoto. QQQ RRR Parent Candidate leftright Sergio Toni Anna Dora Giulio RiccardoGuido Maria Roberto Sergio Toni Anna Dora Giulio Riccardo Guido Maria Roberto Caso b- il nodo da eliminare ha il sotto albero destro vuoto. La procedura è analoga alla precedente.
57
Pseudo Codice IF EmptyTree(NodesLeftTree(Candidate)) THEN LinkParent(Candidate, NodesRightTree(Candidate), Parent, Tree) ELSE IF EmptyRight(NodesRightTree(Candidate)) THEN LinkParent(Candidate, NodesLeftTree(Candidate), Parent, Tree) ELSE continua a riorganizzare lalbero PROCEDURE LinkParent (OldChild, NewChild, Parent: BSTP;VAR Tree: BSTType); {riorganizza lalbero BST dopo leliminazione di un nodo} QQQ RRR Parent Candidate leftright
58
Search(Tree, KeyValue, TNode, Parent) Se la procedura Search restituisce come valore di Parent NIL allora questo significa che è la root di Tree che deve essere cancellata e quindi Tree deve assumere il valore di NewChild. Se non è così allora il sotto albero di Parent, che abbiamo chiamato OldChild deve ora assumere il valore di NewChild. IF Parent = NIL THEN Tree NewChild ELSE IF OldChild = NodesLeftTree(Parent) THEN Parent^.Left NewChild ELSE Parent^Right NewChild
59
Riassunto dei tipi di cancellazione New Old Parent Old New PROCEDURE DeleteTNode(KeyValue:KItemType;VAR Tree: BSTType; VAR Done:boolean); {elimina il nodo con chiave KeyValue ricostruendo la struttura BST. Se il Nodo non esiste Done risulta False}
60
Nel caso in cui il Nodo da cancellare ha sia il sotto albero di sinistra che quello di destra allora si procede come segue: si sostituisce al nodo da cancellare o il nodo di valore maggiore del suo sottoalbero di sinistra o quello di valore minore del suo sotto albero di destra. Se questo nodo ha a sua volta un sottoalbero di destra e uno di sinistra ci si comporta nei suoi confronti come se fosse un nodo da cancellare e quindi si esegue la stessa procedura sopra descritta. Nodo da cancellare 30 5 3 40 35 80 38 8 35 5 3 40 35 80 38 8
61
Pseudo Codice OldCandidate Candidate Search(NodesRightTree(OldCandidate), KeyValue, Dummy, Candidate) OldCandidate^.Info Candidate^.Info OldCandidate^.Key Candidate^.Key GetNodesKey(Candidate, CandsKey) Search(NodesRightTree(OldCandidate), CandsKey, Dummy, Parent) IF Parent = NIL THEN LinkParent(Candidate,NodesRightTree(Candidate), OldCandidate, Tree) ELSE LinkParent(Candidate,NodesRightTree(Candidate), Parent, Tree) Restituisce il nodo del sottoalbero destro con la chiave più piccola Restituisce il nodo genitore di Candidate
62
PROCEDURE LinkParent(OldChild, NewChild, Parent: BSTP; VAR Tree:BSTType); {collega il nodo genitore con il sottoalbero connesso al nodo da cancellare} BEGIN IF Parent=NIL THEN{sostituiamo la root} Tree:= NewChild ELSE IF OldChild = NodesLeftTree(Parent) THEN Parent^.Left:=NewChild{sostituiamo al genitore il figlio sinistro} ELSE Parent^.Right:=NewChild{sostituiamo al genitore il figlio destro} END;
63
PROCEDURE GetNewCandidate(KeyValue: KItemType; VAR Candidate:BSTP; VAR Tree:BSTType); VAR Dummy, {variabile ausiliare per la chiamata alla Search} Parent, OldCandidate :BSTP; CandsKey: KItemType: BEGIN OldCandidate := Candidate Search(NodesRightTree(OldCandidate), KeyValue, Dummy, Candidate) OldCandidate^Info := Candidate^Info ; OldCandidate^Key := Candidate^Key; GetNodesKey(Candidate, CandsKey); Search(NodesRightTree(OldCandidate), CandsKey, Dummy, Parent); IF Parent= NIL THEN LinkParent(Candidate,NodesRightTree(Candidate), OldCandidate, Tree) ELSE LinkParent(Candidate,NodesRightTree(Candidate), Parent, Tree) END;
64
PROCEDURE DeleteTNode(KeyValue: KItemType; VAR Tree:BSTType; VAR Done:boolean); VAR Candidate, {puntatore al nodo candidato per la cancellatura} Parent, {puntatore al genitore del nodo candidato} OldCandidate :BSTP; CandsKey: KItemType: BEGIN Search(Tree, KeyValue, Candidate, Parent) GetNodesKey(Candidate, CandsKey); IF CandsKey<> KeyValue THEN Done:=FALSE ELSE IF EmptyTree(NodesLeftTree(Candidate)) THEN LinkParent(Candidate, NodesRightTree(Candidate), Parent, Tree) ELSE IF EmptyRight(NodesRightTree(Candidate)) THEN LinkParent(Candidate, NodesLeftTree(Candidate), Parent, Tree) ELSE GetNewCandidate(KeyValue, Candidate, Tree); KillTNode(Candidate); Done:= TRUE END END;
65
90 5095 30 34 40 36 17 93 98 100 15 13 35 47 Search(Tree, KeyValue, Candidate, Parent) GetNodesKey(Candidate, CandsKey); IF CandsKey<> KeyValue THEN Done:=FALSE ELSE IF EmptyTree(NodesLeftTree(Candidate)) THEN LinkParent(Candidate, NodesRightTree(Candidate), Parent, Tree) ELSE IF EmptyRight(NodesRightTree(Candidate)) THEN LinkParent(Candidate, NodesLeftTree(Candidate), Parent, Tree) ELSE GetNewCandidate(KeyValue, Candidate, Tree); KillTNode(Candidate); Done:= TRUE Cancellare il nodo 30 OldCandidate := Candidate Search(NodesRightTree(OldCandidate), KeyValue, Dummy, Candidate) OldCandidate^.Info := Candidate^.Info ; OldCandidate^.Key := Candidate^.Key; GetNodesKey(Candidate, CandsKey); Search(NodesRightTree(OldCandidate), CandsKey, Dummy, Parent); IF Parent = NIL THEN LinkParent(Candidate,NodesRightTree(Candidate), OldCandidate, Tree) ELSE LinkParent(Candidate,NodesRightTree(Candidate), Parent, Tree) END; P30 P4030P34 34 P34 34 P36 38 34 P34 P35 P36
66
ALGORITMI DI ATTRAVERSAMENTO DI BST Algoritmi di attraversamento di un albero: LNR - (LeftNodeRight) - Attraversamento inorder Per ogni nodo 1 - Visita il sottoalbero sinistro 2 - Visita il nodo root 3 - Visita il sottoalbero destro NLR - (NodeLeftRight) - Attraversamento pre-order Per ogni nodo 1 - Visita il nodo root 2 - Visita il sottoalbero sinistro 3 - Visita il sottoalbero destro LRN - (LeftRightNode) - Attraversamento post-order Per ogni nodo 1 - Visita il sottoalbero sinistro 2 - Visita il sottoalbero destro 3 - Visita il nodo root
67
LNR - (LeftNodeRight) - Attraversamento ordinato Per ogni nodo 1 - Visita il sottoalbero sinistro 2 - Visita il nodo 3 - Visita il sottoalbero destro PROCEDURE Traverse(Root) IF root <> NIL THEN Traverse(Root^.Left){visita tutti i nodi del sottoalbero sinistro} Visit(Root) Traverse(Root^.Right) {visita tutti i nodi del sottoalbero destro}
68
PROCEDURE Traverse(Root) IF root <> NIL THEN Visit(Root) Traverse(Root^.Left){visita tutti i nodi del sottoalbero sinistro} Traverse(Root^.Right) {visita tutti i nodi del sottoalbero destro} NLR - (NodeLeftRight) - Attraversamento pre-ordinato Per ogni nodo 1 - Visita il nodo root 2 - Visita il sottoalbero sinistro 3 - Visita il sottoalbero destro
69
PROCEDURE Traverse(Root) IF root <> NIL THEN Traverse(Root^.Left){visita tutti i nodi del sottoalbero sinistro} Traverse(Root^.Right) {visita tutti i nodi del sottoalbero destro} Visit(Root) LRN - (LeftRightNode) - Attraversamento post-ordinato Per ogni nodo 1 - Visita il sottoalbero sinistro 2 - Visita il sottoalbero destro 3 - Visita il nodo root
70
Problema Eliminare un BST senza lasciare spazzatura. Soluzione Attraversa lalbero con un algoritmo LRN (post-order) e cancella ogni nodo incontrato. E utilizzato lLRN perché la root è sempre lultima ad essere deallocata dopo aver deallocato i nodi figli, e quindi nessun link è eliminato prima del dovuto. PROCEDURE KillTree(VAR Tree:BSTType); BEGIN IF NOT EmptyTree(Tree) THEN BEGIN KillTree(NodesLeftTree(Tree); KillTree(NodesRightTree(Tree); KillTNode(Tree) END END; Sergio Toni Anna Dora Giulio RiccardoGuido Maria Roberto
71
Problema Espressioni aritmetiche. Notazione Polacca Inversa 5 3 * 4 1 - / Visita LRN post-order Notazione Polacca Diretta / * 5 3 - 4 1 Visita NLR pre-order / * 5 3 - 41 Notazione infissa (5*3)/(4-1) Visita LNR inorder / * 5 3 - 41 / * 5 3 - 41
72
* / - 5 3 41 Problema Assegnata una espressione in notazione polacca diretta scrivere una procedura che costruisca lalbero BST di figura. I dati vengono inseriti uno di seguito allaltro e lelaborazione parte quando digitiamo Utilizzare un algoritmo del tipo post-order (LRN). (5*3)/(4-1). Albero di computazione
73
PROGRAM EvaluateTree(input, output); TYPE NoteP=^ExpressionNode; ExpressionNode = RECORD Token: char; {un operatore o un carattere tra 0..9} Operand1; {puntatore alla espressione a sinistra} Operand2; {puntatore alla espressione a destro} NodeP END; VAR Etree: NodeP; PROCEDURE MakeTree(ETree:NodeP); {costruisce un albero a partire dalla espressione di input in forma PN secondo la strategia NLR} BEGIN…..END; FUNCTION TreesValue(ETree: NodeP):integer; {ritorna il valore dellespressione rappresentata dallalbero ETree secondo la strategia LRN} BEGIN…..END; { -------------------- BODY ----------------------- } BEGIN new(ETree); MakeTree(ETree); readln; write(Il valore dellespressione è ); writeln(TresValue(ETree):1) END. Allochiamo spazio per lalbero Variabile passata per valore così che alluscita puntiamo di nuovo alla root
74
Pseudo codice di MakeTree SkipBlancks(Ch){salta i blank e ritorna invece blank quando incontra } IF Ch<> THEN WITH ETree^ DO Token Ch IF Token è un operatore THEN costruisci il sotto albero sinistro costruisci il sotto albero destro Si può facilmente realizzare con ricerca di appartenenza a un dato insieme Si costruiscono mediante chiamate ricorsive alla procedura MakeTree
75
PROCEDURE SkipBlanks(VAR Ch:char); {salta i blank e ritorna invece blanck quando incontra EOLN} BEGIN Ch:= ; WHILE NOT eoln AND (Ch= ) DO read(Ch) END; PROCEDURE MakeTree(ETree: NodeP); {costruzione dellalbero dellespressione} VAR Ch: char; BEGIN SkipBlancks(Ch); IF Ch <> THEN WITH ETree^ DO BEGIN Token:=Ch; IF Token IN [*,/,\,+,-] THEN BEGIN new(Operand1); MakeTree(Operand1); new(Operand2); MakeTree(Operand2); END END; Carattere candidato come tokenAssegna a token la root attuale Verifica che il token sia un operatore Crea lalbero sinistro Crea lalbero destro
76
Pseudo codice per ExpressionValue {dato un operatore si cercano gli operandi nei sotto-alberi sinistro e destro; quindi si applica loperazione indicata nel nodo radice. In questo caso applichiamo una strategia LRN. La procedura è ricorsiva e il case base si ha quando il nodo a cui siamo giunti rappresenta un singolo operando. Per sapere questo facciamo una chiamata alla funzione NumericValue} WITH ETree^ DO IF Token rappresenta un letterale intero THEN TreeValues NumericValue(Token) ELSE LeftOperand TreesValue(Operand1) RightOperand TreesValue(Operand2) TreesValue ExpressionValue(LeftOperand,RightOperand, Token))
77
FUNCTION ExpressionValue(Operand1, Operand2:integer; Operator:char): integer; BEGIN CASE Operator OF *: ExpressionValue:=Operand1*Operand2; /: ExpressionValue:=Operand1 DIV Operand2; \: ExpressionValue:=Operand1 MOD Operand2; +: ExpressionValue:=Operand1 + Operand2; -: ExpressionValue:=Operand1 - Operand2 END END; FUNCTION NumericValue(Ch:char):integer; BEGIN NumericValue:= ord(Ch) - ord(0) END;
78
FUNCTION TreesValue(ETree:NodeP): integer; VAR LeftOperand, RightOperand: integer; BEGIN WITH ETree^ DO IF Token IN [0..9] THEN TreesValue:=NumericValue(Token); ELSE BEGIN LeftOperand:=TreeValue(Operand1); RightOperand:=TreeValue(Operand2); TreesValue:= ExpressionValue(LeftOperand,RightOperand, Token) END END;
Presentazioni simili
© 2024 SlidePlayer.it Inc.
All rights reserved.