Algoritmi e strutture dati

Documenti analoghi
Algoritmi e strutture dati

Strutture dati per insiemi disgiunti


Alberi binari e alberi binari di ricerca

Union-find. Insiemi disgiunti. F. Damiani - Alg. & Lab. 04/05 (da C. Demetrescu et al - McGraw-Hill)

I B+ Alberi. Sommario

LE STRUTTURE DATI DINAMICHE: GLI ALBERI. Cosimo Laneve

Strutture dati per insiemi disgiunti (union-find)

Heap e code di priorità

alberi completamente sbilanciati

Un albero completamente bilanciato o pieno (full) alberi completamente sbilanciati. Un albero binario completo

Alberi n-ari: specifiche sintattiche e semantiche. Realizzazioni. Visita di alberi n-ari.

Esercizi Capitolo 10 - Code con priorità e insiemi disgiunti

Alberi ed Alberi Binari

Esercizi Capitolo 10 - Code con priorità e insiemi disgiunti

Per semplicità eliminiamo le ripetizioni nell'albero.

Implementazione dell albero binario in linguaggio C++

Algoritmi Greedy. Tecniche Algoritmiche: tecnica greedy (o golosa) Un esempio

ADT Coda con priorità

Esercizi su alberi binari

Problema Union-Find. 1. Il problema Union-Find. Problema Union-Find Pag. 1/18

Sommario. Le strutture dati elementari per implementare sequenze: Vettori Liste

Alberi binari di ricerca

Appunti Senza Pretese di Programmazione II: Costruzione di un Albero Bilanciato

ADT Dizionario. Ordered search table. Supponiamo che sia definita una relazione d'ordine totale sulle chiavi del dizionario D:

Lezione 12 Tabelle Hash

Esercizio 1. E vero che in un AVL il minimo si trova in una foglia o nel penultimo livello? FB = -1. livello 0 FB = -1. livello 1 FB = -1.

Alberi e alberi binari I Un albero è un caso particolare di grafo

Alberi Binari di Ricerca

RISOLUZIONE IN LOGICA PROPOSIZIONALE. Giovanna D Agostino Dipartimento di Matemaica e Informatica, Università di Udine

Alberi Binari di Ricerca

Strutture di accesso ai dati: B + -tree

Un esempio: l ADT Dizionario (mutabile) Definizione. Alberi binari di ricerca (BST = binary search tree) search(chiave k) -> elem

Problemi di ordinamento

Algoritmi e Strutture Dati

Alberi. Alberi: definizioni. Alberi Binari. Esercizi su alberi binari: metodi ricorsivi. Struttura dati per alberi generici. ASD-L - Luca Tesei

Alberi di ricerca. Alberi binari di ricerca. F. Damiani - Alg. & Lab. 04/05 (da C. Demetrescu et al - McGraw-Hill)

Informatica 3. Informatica 3. LEZIONE 17: Alberi generici. Lezione 17 - Modulo 1. Introduzione. ADT dell albero generico.

Grafi (non orientati e connessi): minimo albero ricoprente

Università degli Studi di L Aquila Facoltà di Scienze M.F.N. Corso di Laurea in Informatica. Modulo di Laboratorio di Algoritmi e Strutture Dati

Insiemi Specifiche, rappresentazione e confronto tra realizzazioni alternative.

In questa lezione Alberi binari di ricerca: la cancellazione

Esercizi Capitolo 6 - Alberi binari di ricerca

Esercizi di Algoritmi e Strutture Dati

Organigramma Gerarchia. (Tree) Nessuna persona può avere più di un superiore Ogni persona può essere superiore di altre

Esercitazione 6. Alberi binari di ricerca

Lezione 9 Alberi binari di ricerca

Una breve introduzione all implementazione in C di algoritmi su grafo

Dizionari Liste invertite e Trie

FILE E INDICI Architettura DBMS

GLI ALBERI BINARI DI RICERCA. Cosimo Laneve

Alberi. Gli alberi sono una generalizzazione delle liste che consente di modellare delle strutture gerarchiche come questa: Largo. Fosco.

Laboratorio di Informatica

Esempio: rappresentare gli insiemi

Ordinamento per inserzione e per fusione

Alberi binari. Alberi binari di ricerca

Algoritmi e Strutture Dati. HeapSort

Laboratorio di Programmazione

Problemi, istanze, soluzioni

Questa soluzione va contemplata quando le lunghezze stimate dalle liste usate sono significativamente maggiori delle dimensioni di un elemento.

Algoritmi (9 CFU) (A.A ) Heap e Algoritmo HeapSort. Prof. V. Cutello Algoritmi 1

Alberi di copertura. Mauro Passacantando. Dipartimento di Informatica Largo B. Pontecorvo 3, Pisa

Grafi: visite. Una breve presentazione. F. Damiani - Alg. & Lab. 04/05 (da C. Demetrescu et al - McGraw-Hill)

Alberi di copertura minimi

Algoritmi e Strutture di Dati (3 a Ed.) String matching. Alan Bertossi, Alberto Montresor

Programmazione I - Laboratorio

Progettazione di algoritmi

Note per la Lezione 4 Ugo Vaccaro

ricerca di un elemento, verifica dell appartenenza di un elemento

Dati e Algoritmi 1: A. Pietracaprina. Grafi (II parte)

Esercizi Capitolo 11 - Strutture di dati e progettazione di algoritmi

Algoritmi e Strutture Dati

Alberi binari (radicati e ordinati) della radice Il padre del nodo 5 e del nodo 3

Dati e Algoritmi I (Pietracaprina) Esercizi sugli Alberi

In questa lezione. Heapsort. ordinamento con complessità, nel caso peggiore, O(nlogn) [CLRS01] cap. 6 da pag. 106 a pag. 114

ALBERI : introduzione SOMMARIO ALBERI ALBERI. ALBERI: introduzione ALBERI BINARI: introduzione VISITE RICORSIVE DI ALBERI

2.2 Alberi di supporto di costo ottimo

Dati e Algoritmi I (Pietracaprina) Esercizi su Alberi Binari di Ricerca e (2,4)-Tree

Algoritmi e Strutture di Dati I 1. Algoritmi e Strutture di Dati I Massimo Franceschet francesc

Un esempio di mutua ricorsione

Albero binario. Alberi binari (introduzione) Terminologia. Alberi di ricerca binaria (BST)

Algoritmi e Strutture Dati

Elezione di un leader in una rete ad anello

Algoritmi e Strutture Dati

Hash Table. Hash Table

Laboratorio di Python

Alberi. Gli alberi sono una generalizzazione delle liste che consente di modellare delle strutture gerarchiche come questa: Largo. Fosco.

Precorsi di matematica

Alberi Binari di Ricerca e Alberi Rosso-Neri

Esercitazione. Ricorsione. May 31, Esercizi presi dal libro di Rosen

Il tipo astratto coda con priorità: specifiche sintattiche e semantiche. Realizzazioni.

Implementazione ADT: Alberi

Alberi. Strutture dati: Alberi. Alberi: Alcuni concetti. Alberi: definizione ricorsiva. Alberi: Una prima realizzazione. Alberi: prima Realizzazione

Basi di Dati e Sistemi Informativi. Organizzazione fisica dei dati. Corso di Laurea in Ing. Informatica Ing. Gestionale Magistrale

ALGORITMI E STRUTTURE DATI

Linked Lists. Liste linkate (1) liste linkate ( stack, queues ), trees. Liste linkate come strutture

2.2 Alberi di supporto di costo ottimo

Laboratorio di Algoritmi e Strutture Dati

Divide et impera su alberi

Strutture dati dinamiche in C (II)

Transcript:

Algoritmi e strutture dati Roberto Cordone A. A. 2015-16

Capitolo 4 Implementazioni delle partizioni Nota: queste dispense sono un rapido riassunto delle lezioni svolte nel dicembre 2015 e gennaio 2016. In buona parte ripetono gli argomenti delle dispense del prof. Goldwurm, con alcune aggiunte, qualche piccola modifica nella presentazione, qualche esempio. Chi notasse errori, incoerenze, oscurità o avesse dubbi è invitato a contattarmi per segnalarli. Si tratta di rappresentare una partizione di un insieme A dato in una collezione di sottoinsiemi disgiunti fra loro, ognuno dei quali ha un elemento rappresentativo. Per esempio, se A = a 1, a 2, a 3, a 4, una possibile partizione è P = a 1, ā 4, a 2, ā 3, dove gli elementi rappresentativi sono evidenziati barrandoli. In termini di algebra eterogenea: dove ([A, PART (A)], [UNION, FIND, ID, a 1,..., a m ]) la funzione FIND riceve una partizione e un elemento e restituisce l elemento rappresentante del sottoinsieme di cui l elemento dato fa parte nella partizione data; la funzione UNION riceve una partizione e due elementi e restituisce una partizione nella quale i due sottoinsiemi di cui fanno parte gli elementi dati sono fusi in uno solo. Un implementazione banale consiste nel descrivere ogni sottoinsieme della partizione con una lista di elementi, magari tenendo in cima il rappresentante: la funzione UNION consiste nel fondere due liste: questo richiede tempo O (n), perché si tratta di spostare tutti gli elementi di una lista nell altra. Si può fare meglio se si usa una lista circolare con un puntatore all ultimo elemento, che permette di appendere una lista all altra in tempo costante O (1); la funzione FIND, però, richiede di scorrere tutte le liste per trovare l elemento, in modo da sapere quale lista lo contiene, e quindi determinarne il rappresentante: tempo O (n). Un altra implementazione banale consiste nel tenere in un vettore l indicazione del rappresentante per ciascun elemento: 1

la funzione FIND richiede tempo costante, perché basta consultare il vettore per avere la risposta cercata; la funzione UNION consiste nello scorrere il vettore e cambiare il rappresentante di uno dei due sottoinsiemi, sostituendolo con il rappresentante dell altro, in modo da fondere i due sottoinsiemi: questo richiede tempo O (n). 4.4 I Merge-Find set (MF-set) Una rappresentazione sofisticata cerca un compromesso fra l efficienza delle due funzioni. Si tratta di vedere la partizione come una foresta, in cui gli elementi sono nodi e in particolare i rappresentanti sono le radici degli alberi. Ogni nodo punta un altro nodo, tranne i rappresentanti che puntano a NULL. Si veda la Figura 4.1. Figura 4.1: Una partizione vista come foresta radicata L implementazione pratica può sfruttare i puntatori, ma in questo caso conviene usare la rappresentazione a vettore, perché la dimensione complessiva della struttura non cambia mai durante l uso (contrariamente ai dizionari che subiscono inserimenti e cancellazioni, per cui una struttura a vettore può essere troppo rigida). Le radici punteranno, anziché a NULL a un indice numerico particolare, come 0 o 1 (se 0 è un indice valido per il vettore) oppure punteranno all indice dell elemento stesso (l elemento i avrà P[i].father == i). Nel seguito, useremo 0 per coerenza con le dispense. struct elemento A *a; /* elemento */ int father; /* indice dell elemento padre */ ; typedef struct elemento MFset[n]; MFset P; dove una partizione P è vista come un vettore di strutture che contengono un elemento e l indice dell elemento padre. Spesso, invece di un vettore di strutture, si usano più vettori separati, uno per ciascun campo. A *a[n]; /* vettore degli elementi */ 2

int father[n]; /* vettore degli indici padre */ La funzione FIND consiste semplicemente nel risalire l albero di cui fa parte l elemento dato, fino a trovare la radice (Figura 4.2). A *FIND (A *a, MFset P) k = KEY(a); while (P[k].father!= 0) k = P[k].father; return P[k].a; ; Figura 4.2: Ricerca del rappresentante di un nodo dato La complessità dipende dal bilanciamento dell albero e dal numero di figli: può essere qualsiasi fra O (1), per alberi in cui tutti gli elementi sono direttamente appesi alla radice; O (n), per alberi in cui ogni elemento è concatenato agli altri a formare una lista. La funzione UNION nella sua forma più semplice consiste nel cercare i due rappresentanti e attaccare uno di loro all altro (per convenzione, ad esempio, il secondo al primo), come nella Figura 4.3. MFset UNION (A *a1, A *a2, MFset P) v1 = FIND(a1); k1 = KEY(v1); v2 = FIND(a2); k2 = KEY(v2); if (k1!= k2) P[k2].father = k1; return P; ; Questo richiede due volte il tempo della funzione FIND più tempo costante. Esercizio: si calcolino le componenti connesse del grafo che ha i seguenti lati: (d, g), (h, b), (b, g), (c, e), (i, l), (d, b), (e, g), (f, c), (e, d) 3

Figura 4.3: Fusione di due sottoinsiemi in uno solo Risultano due alberi, uno di altezza 4 radicato in f e l altro di altezza 1 radicato in i e contenente i e l. Tutto dipende quindi da quanto si riesce a tenere piatto ciascun albero della foresta, cioè a limitare l altezza massima dei suoi alberi. Ci sono diversi modi per garantire questo risultato. Bilanciamento basato sulla cardinalità L idea base è appendere sempre l albero di cardinalità minore a quello di cardinalità maggiore, anziché banalmente il secondo al primo. Si può dimostrare per induzione che questo limita l altezza di ogni albero a log 2 n + 1. per n = 1, l albero ha solo la radice, cioè un livello, che è h (1) = 1 log 2 1 + 1. se la tesi vale per ogni i < n, significa che vale per i due sottoalberi che fondiamo in una applicazione della funzione UNION, che hanno cardinalità n 1 e n 2 positive e tali che n 1 + n 2 = n; supponiamo n 1 < n 2, per cui appendiamo T 1 a T 2 ; inoltre n 1 < n 2 e n 1 + n 2 = n implica 2n 1 < n, mentre n 2 n; l albero risultante dalla fusione ha altezza pari al massimo fra quella di T 1 aumentata di 1 e quella di T 2 : h (n) = max (h (n 1 ) + 1, h (n 2 )) entrambe le altezze rispettano la tesi, per cui h (n) h (n 1 ) + 1 log 2 n 1 + 2 < log 2 n/2 + 2 = log 2 n + 1 h (n) h (n 2 ) log 2 n 2 + 1 < log 2 n + 1 che è la tesi. h (n) log 2 n + 1 Questo meccanismo richiede di conservare nei MF-set anche la cardinalità degli alberi: basta aggiungere un campo num ad ogni struttura, che indica (per i soli elementi rappresentanti) la cardinalità dell albero appeso. MFset UNION (A *a1, A *a2, MFset P) v1 = FIND(a1); k1 = KEY(v1); v2 = FIND(a2); k2 = KEY(v2); 4

if (k1!= k2) if (P[k1].num < P[k2].num) P[k1].father = k2; P[k2].num = P[k1].num + P[k2].num; P[k1].num = 0; /* non strettamente necessario */ else P[k2].father = k1; P[k1].num = P[k1].num + P[k2].num; P[k2].num = 0; /* non strettamente necessario */ return P; ; Esercizio: si calcolino le componenti connesse del grafo che ha i seguenti lati: (d, g), (h, b), (b, g), (c, e), (i, l), (d, b), (e, g), (f, c), (e, d) Risultano due alberi, uno di altezza 2 radicato in h e l altro di altezza 1 radicato in i e contenente i e l. Bilanciamento basato sull altezza Invece di considerare la cardinalità, ci si può concentrare su ciò che effettivamente interessa, cioè l altezza degli alberi, appendendo sempre l albero di altezza minore a quello di altezza maggiore (in caso di parità, il secondo al primo); L albero risultante ha altezza pari alla maggiore delle due, se sono diverse; a entrambe più 1 se sono uguali. Questo comporta un campo rank, analogo al campo num prima introdotto; MFset UNION (A *a1, A *a2, MFset P) v1 = FIND(a1); k1 = KEY(v1); v2 = FIND(a2); k2 = KEY(v2); if (k1!= k2) if (P[k1].rank < P[k2].num) P[k1].father = k2; P[k1].rank = 0; /* non strettamente necessario */ else P[k2].father = k1; if (P[k1].rank == P[k2].rank) P[k1].rank = P[k1].rank + 1; 5

P[k2].num = 0; /* non strettamente necessario */ return P; ; Anche questa strategia garantisce un altezza logaritmica rispetto al numero di elementi. Esercizio: si calcolino le componenti connesse del grafo che ha i seguenti lati: (d, g), (h, b), (b, g), (c, e), (i, l), (d, b), (e, g), (f, c), (e, d) Risultano gli stessi due alberi ottenuti con il bilanciamento in cardinalità. Euristica di compressione dei cammini Ogni volta che si esegue la funzione FIND si percorre una catena di nodi che sarebbe meglio poter spianare appendendoli tutti alla radice. Questo è banalmente possibile: basta ripetere due volte la catena 1. la prima volta per trovare la radice; 2. la seconda volta per appendere ciascun nodo della catena alla radice. Questo comporta l uso del campo rank e l integrazione della funzione FIND come segue: A *FIND (A *a, MFset P) /* si determina la radice dell albero */ k = r = KEY(a); while (P[r].father!= 0) r = P[r].father; /* si appende direttamente ogni nodo della catena all albero */ while (P[k].father!= 0) p = P[k].father; P[k].father = r; k = p; return P[r].a; ; Se si modifica in questo modo la funzione FIND, ovviamente, il suo tempo di esecuzione raddoppia. Tuttavia, dato che essa viene usata nella funzione UNION, una sequenza di UNION tenderà a creare una foresta molto più piatta, e quindi le esecuzioni successive diventano molto più rapide. Si può dimostrare che l altezza della foresta tende a diventare praticamente costante al crescere di n. Infatti, 1 per k = 0 h (n) min k N : n F (k) con F (k) = 2 F (k 1) per k 1 6

Siccome F cresce velocissima (1, 2, 4, 16, 2 16, 2 216,...), praticamente (n) 5 in qualsiasi situazione. Esercizio: si calcolino le componenti connesse del grafo che ha i seguenti lati: (d, g), (h, b), (b, g), (c, e), (i, l), (d, b), (e, g), (f, c), (e, d) Il lato (b, g) fa anche collegare direttamente g ad h; Il lato (e, d) non fonde sottoinsiemi, ma applica la compressione e rende la foresta completamente piatta: due alberi di altezza 1 7