Implementazione di dizionari Problema del dizionario dinamico Scegliere una struttura dati in cui memorizzare dei record con un campo key e alcuni altri.

Slides:



Advertisements
Presentazioni simili
Strutture dati per insiemi disgiunti
Advertisements

Algoritmi e Strutture Dati
Tecnologia delle basi di dati: Strutture fisiche di accesso
© 2007 SEI-Società Editrice Internazionale, Apogeo Unità E1 Dallanalisi del problema alla definizione dellalgoritmo.
Estendere i linguaggi: i tipi di dato astratti
Algoritmi e Programmazione
INSIEMI INSIEME= gruppo di oggetti di tipo qualsiasi detti elementi dell’insieme. Un insieme è definito quando viene dato un criterio non ambiguo che.
Hash Tables Indirizzamento diretto Tabelle Hash
Hash Tables Indirizzamento diretto Tabelle Hash Risoluzioni di collisioni Indirizzamento aperto.
Alberi binari di ricerca
Capitolo 3 Strutture dati elementari Algoritmi e Strutture Dati.
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Copyright © The McGraw - Hill Companies, srl 1 Ordinamenti lineari.
Capitolo 3 Strutture dati elementari Algoritmi e Strutture Dati.
U V U V (a) |cfc|=2 prima e dopo (b) |cfc|=2 prima e |cfc|=1 dopo
Il problema del dizionario
Camil Demetrescu, Irene Finocchi, Giuseppe F. ItalianoAlgoritmi e strutture dati Algoritmi e Strutture Dati Capitolo 2 Modelli di calcolo e metodologie.
Capitolo 7 Tavole hash Algoritmi e Strutture Dati.
Interrogazioni su un albero binario di ricerca Search(S,k) – dato un insieme S ed un valore chiave k restituisce un puntatore x ad un elemento in S tale.
Capitolo 7 Tavole hash Algoritmi e Strutture Dati.
Appunti di inferenza per farmacisti
Algoritmi e Strutture Dati Alberi Binari di Ricerca.
Alberi di Ricorrenza Gli alberi di ricorrenza rappresentano un modo conveniente per visualizzare i passi di sostitu- zione necessari per risolvere una.
Algoritmi e Strutture Dati (Mod. B)
Numeri razionali I numeri RAZIONALI sono i numeri che possono essere rappresentati come frazioni. I razionali comprendono i numeri interi e quelli decimali.
1 2. Analisi degli Algoritmi. 2 Algoritmi e strutture dati - Definizioni Struttura dati: organizzazione sistematica dei dati e del loro accesso Algoritmo:
Hashing.
Hashing.
Introduzione alla programmazione lll
07/04/2003Algoritmi Ricerca in una sequenza di elementi Data una sequenza di elementi, occorre verificare se un elemento fa parte della sequenza oppure.
Tabelle hash.
Modelli simulativi per le Scienze Cognitive
Modello dati ALBERO Albero: Albero: insieme di punti chiamati NODI e linee chiamate EDGES EDGE: linea che unisce due nodi distinti Radice (root): in una.
Heap allocation e garbage collector di Oberon Algoritmo Quick Fit e garbage collector mark and sweep.
Heap binomiali Gli heap binomiali sono strutture dati su cui si possono eseguire efficientemente le operazioni: Make(H) : crea uno heap vuoto Insert(H,
memoria gestita staticamente:
Algoritmi e Programmazione Avanzata
Tavole dinamiche Spesso non si sa a priori quanta memoria serve per memorizzare dei dati in un array, in una tavola hash, in un heap, ecc. Può capitare.
Anche la RB-Delete ha due fasi: Nella prima viene tolto un nodo y avente uno dei sottoalberi vuoto sostituendolo con la radice dellaltro sottoalbero. Per.
Metodo della moltiplicazione
Elementi di Informatica di base
Esercizio 10.* Un cassiere vuole dare un resto di n centesimi di euro usando il minimo numero di monete. a) Descrivere un algoritmo goloso per fare ciò.
Strutture dati per insiemi disgiunti
Radix-Sort(A,d) // A[i] = cd...c2c1
Hashing.
Passo 3: calcolo del costo minimo
Ispezione lineare La funzione hash h(k,i) si ottiene da una funzione hash ordinaria h'(k) ponendo L’esplorazione inizia dalla cella h(k,0) = h'(k) e continua.
Per valutare la complessità ammortizzata scomponiamo ogni Union: nelle due FindSet e nella Link che la costituiscono e valuteremo la complessità in funzione.
La complessità media O(n log n) di Quick-Sort vale soltanto se tutte le permutazioni dell’array in ingresso sono ugualmente probabili. In molte applicazioni.
Unità 2 Distribuzioni di probabilità Misure di localizzazione Misure di variabilità Asimmetria e curtosi.
Capitolo 7 Tavole hash Algoritmi e Strutture Dati Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano.
Valutare la difficoltà dei problemi
Rappresentazione dell’informazione nel calcolatore.
Parte 3 Lo stato: variabili, espressioni ed assegnazioni

Fondamenti di Informatica 2 Ingegneria Informatica Docente: Giovanni Macchia a.a
Risoluzione delle collisioni con indirizzamento aperto Con la tecnica di indirizzamento aperto tutti gli elementi stanno nella tavola. La funzione hash.
Ordinamento in tempo lineare Il limite inferiore Ω(n log n) vale per tutti gli algoritmi di ordinamento generali, ossia per algoritmi che non fanno alcuna.
Hashing. 2 argomenti Hashing Tabelle hash Funzioni hash e metodi per generarle Inserimento e risoluzione delle collisioni Eliminazione Funzioni hash per.
Algoritmi e Strutture Dati
1 Analisi ammortizzata Si considera il tempo richiesto per eseguire, nel caso pessimo, una intera sequenza di operazioni. Se le operazioni costose sono.
Intelligenza Artificiale Risoluzione di Problemi
Capitolo 7 Tavole hash Algoritmi e Strutture Dati Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano.
Rappresentazione dell'informazione
Conversione binario-ottale/esadecimale
Problemi risolvibili con la programmazione dinamica Abbiamo usato la programmazione dinamica per risolvere due problemi. Cerchiamo ora di capire quali.
Complessità Computazionale
“ Pseudocodice ” Un programma per computer lavorerà su in insieme di “ variabili ” contenenti i dati del problema, soluzioni intermedie, soluzioni finali.
Informatica Problemi e algoritmi. una situazione che pone delle domande cui si devono dare risposte. Col termine problema o situazione problematica s’indica.
In alcuni casi gli esiti di un esperimento possono essere considerati numeri naturali in modo naturale. Esempio: lancio di un dado In atri casi si definisce.
Transcript della presentazione:

Implementazione di dizionari Problema del dizionario dinamico Scegliere una struttura dati in cui memorizzare dei record con un campo key e alcuni altri campi in cui sono memorizzati i dati associati alla chiave key. Su tale struttura si devono poter eseguire in modo efficiente le operazioni: Insert che aggiunge un nuovo record Search che cerca un record di chiave key Delete che toglie un record dalla struttura

Tavole ad indirizzamento diretto Funzionano bene quando le chiavi sono degli interi positivi non troppo grandi. Ad esempio se le chiavi appartengono all’insieme U = {0,1,...,m-1} (con m non troppo grande) possiamo usare un array T[0..m-1] in cui ogni posizione (cella) T[k] corrisponde ad una chiave k. Generalmente T[k] è un puntatore al record con chiave k. Se la tavola non contiene un record con chiave k allora T[k] = nil.

La realizzazione delle operazioni in tempo costante O(1) è semplice: Search(T,k) return T[k] Insert(T,x) T[x.key] = x Delete(T,x) T[x.key] = nil

Con l’indirizzamento diretto occorre riservare memoria sufficiente per tante celle quante sono le possibili chiavi. Se l’insieme U delle possibili chiavi è molto grande l’indirizzamento diretto è inutilizzabile a causa delle limitazioni di memoria. Anche quando la memoria sia sufficiente se le chiavi memorizzate nel dizionario sono soltanto una piccola frazione di U la maggior parte della memoria riservata risulta inutilizzata. Inconvenienti

Tavole hash Una tavola hash richiede memoria proporzionale al numero massimo di chiavi presenti nel dizionario indipendentemente dalla cardinalità dell’insieme U di tutte le possibili chiavi. In una tavola hash di m celle ogni chiave k viene memorizzata nella cella h(k) usando una funzione h : U  {0..m-1} detta funzione hash.

Siccome |U| > m esisteranno molte coppie di chiavi distinte k 1 ≠ k 2 tali che h(k 1 ) = h(k 2 ). Diremo in questo caso che vi è una collisione tra le due chiavi k 1 e k 2. Nessuna funzione hash può evitare le collisioni. Dovremo quindi accontentarci di funzioni hash che minimizzino la probabilità delle collisioni e, in ogni caso, dovremo prevedere qualche meccanismo per gestire le collisioni.

k1k1 k3k3 k5k5 k4k4 k2k2 U Risoluzione delle collisioni con liste Gli elementi che la funzione hash manda nella stessa cella vengono memorizzati in una lista La tavola hash è un array T[0..m-1] di m puntatori alle cime delle liste nil T k1k1 k2k2 k3k3 h(k)h(k) k3k3 k4k4 k2k2 k5k5

Delete(T,x) “togli x dalla lista T[h(x.key)]” La realizzazione delle operazioni è facile: Search(T,k) “cerca nella lista T[h(k)] un elemento x tale che x.key == k” return x Insert(T,x) “aggiungi x alla lista T[h(x.key)]”

Delete richiede una ricerca con Search dopo di che l’eliminazione dell’elemento dalla lista si può realizzare in tempo O(1) Search richiede tempo proporzionale alla lunghezza della lista T[h(k)] Insert si può realizzare in tempo O(1)

Analisi di hash con liste Valutiamo la complessità media di Search in funzione del fattore di carico α = n/m. Siccome n è compreso tra 0 e |U| 0 ≤ α ≤ |U|/m. Una Search di un elemento con chiave k richiede tempo O(n) nel caso pessimo in cui tutti gli n elementi stanno nella stessa lista h(k) della chiave cercata. Supponiamo che la tavola hash T abbia m celle e che in essa siano memorizzati n elementi.

“ogni elemento in input ha la stessa probabilità di essere mandato in una qualsiasi delle m celle” Supporremo che h(k) distribuisca in modo uniforme le n chiavi tra le m liste. Più precisamente assumeremo la seguente ipotesi di hash uniforme semplice.

Siano n 0,n 1,...,n m-1 le lunghezze delle m liste. La lunghezza attesa di una lista è Proprietà: Nell’ipotesi di hash uniforme semplice la ricerca di una chiave k non presente nella tavola hash richiede tempo  (1+α) in media.

Nell’ipotesi di hash uniforme semplice E[n j ] = α e quindi l’algoritmo richiede tempo medio  (1+α). Dimostrazione: La Search calcola j =h(k) (tempo  (1)) e poi controlla tutti gli n j elementi della lista T[j] (tempo  (n j )).

Proprietà: Nell’ipotesi di hash uniforme semplice la ricerca di una chiave k presente nella tavola hash richiede tempo  (1+α) in media. Dimostrazione: Assumiamo che ogni chiave presente nella tavola abbia la stessa probabilità di essere la chiave cercata.

Una ricerca di un una chiave k presente nella tavola richiede il calcolo dell’indice j = h(k), il test sulle chiavi che precedono k nella lista T[j] e infine il test su k (numero operazioni = 2 + numero elementi che precedono k nella lista). Le chiavi che precedono k nella lista T[j] sono quelle che sono state inserite dopo di k.

Nell’ipotesi di hash uniforme semplice E(X i,j ) = 1/m. Supponiamo che k = k i sia l’i-esima chiave inserita nella lista. Per j = i +1,...,n sia X i,j la variabile casuale che vale 1 se k j viene inserita nella stessa lista di k e 0 altrimenti

Il valore atteso del numero medio di operazioni eseguite è Se n ≤ cm per qualche costante positiva c allora α = O(1) e  (1+α) =  (1).

Funzioni hash Essa dovrebbe soddisfare l’ipotesi di hash uniforme semplice: “Ogni chiave ha la stessa probabilità 1/m di essere mandata in una qualsiasi delle m celle, indipendentemente dalle chiavi inserite precedentemente” Che proprietà deve avere una una buona funzione hash?

Sfortunatamente l’ipotesi di hash uniforme semplice dipende dalle probabilità con cui vengono estratti gli elementi da inserire; probabilità che in generale non sono note. Ad esempio, se le chiavi sono numeri reali x estratti casualmente e indipendentemente da una distribuzione di probabilità uniforme in 0 ≤ x < 1 allora h(x) =  mx  soddisfa tale condizione.

Le funzioni hash che descriveremo assumono che le chiavi siano degli interi non negativi. Questo non è restrittivo in quanto ogni tipo di chiave è rappresentato nel calcolatore con una sequenza di bit e ogni sequenza di bit si può interpretare come un intero non negativo.

Metodo della divisione h(k) = k mod m Una buona scelta per m è un numero primo non troppo vicino ad una potenza di 2. Ad esempio m = 701. Difetto: non “funziona bene” per ogni m. Ad esempio se m = 2 p è una potenza di due allora k mod m sono gli ultimi p bit di k. In generale anche valori di m prossimi ad una potenza di 2 non funzionano bene.

Metodo della moltiplicazione h(k) =  m(kA mod 1)  in cui A è una costante reale con 0 < A < 1 ed x mod 1 = x –  x  è la parte frazionaria. Vantaggi : la scelta di m non è critica e nella pratica funziona bene con tutti i valori di A anche se ci sono ragioni teoriche per preferire l’inverso del rapporto aureo

h(k) si calcola facilmente se si sceglie m = 2 p e A = q/2 w con 0 < q < 2 w dove w è la lunghezza di una parola di memoria. k q  = r1r1 w bit h(k)h(k) p bit r0r0

Randomizzazione di funzioni hash Più seriamente: per ogni funzione hash si possono trovare delle distribuzioni di probabilità degli input per le quali la funzione non ripartisce bene le chiavi tra le varie liste della tavola hash. Nessuna funzione hash può evitare che un avversario malizioso inserisca nella tavola una sequenza di valori che vadano a finire tutti nella stessa lista.

Possiamo usare la randomizzazione per rendere il comportamento della tavola hash indipendente dall’input. L’idea è quella di usare una funzione hash scelta casualmente in un insieme “universale” di funzioni hash. Questo approccio viene detto hash universale.

Un insieme H di funzioni hash che mandano un insieme U di chiavi nell’insieme {0,1,...,m-1} degli indici della tavola hash si dice universale se: “per ogni coppia di chiavi distinte j e k vi sono al più |H|/m funzioni hash in H tali che h(j) = h(k)” Se scegliamo casualmente la funzione hash in un insieme universale H la probabilità che due chiavi qualsiasi j e k collidano è 1/m, la stessa che si avrebbe scegliendo casualmente le due celle in cui mandare j e k.

Proprietà : Supponiamo che la funzione hash h sia scelta casualmente in un insieme universale H e venga usata per inserire n chiavi in una tavola T di m celle e sia k una chiave qualsiasi. La lunghezza attesa E[n h(k) ] della lista h(k) è α = n/m se k non è presente nella tavola ed è minore di α+1 se k è presente. Quindi, indipendentemente dalla distribuzione degli input, una Search richiede tempo medio  (1+α) che, se n = O(m), è  (1).