Hash heap visite, Esercizi di Algoritmi E Programmazione Avanzata
roberto_musa
roberto_musa

Hash heap visite, Esercizi di Algoritmi E Programmazione Avanzata

27 pagine
1Numero di download
563Numero di visite
Descrizione
Esercitazione su Tabelle di Hash, Heap e Visite dei Grafi
20 punti
Punti download necessari per scaricare
questo documento
Scarica il documento
Anteprima3 pagine / 27
Questa è solo un'anteprima
3 pagine mostrate su 27 totali
Questa è solo un'anteprima
3 pagine mostrate su 27 totali
Questa è solo un'anteprima
3 pagine mostrate su 27 totali
Questa è solo un'anteprima
3 pagine mostrate su 27 totali

1 Inserimento in tabella hash Si consideri una tabella hash di dimensione m = 11 inizialmente vuota. Si mostri il contenuto della tabella dopo aver inserito nell’ordine, i valori 33, 10, 24, 14, 16, 13, 23, 31, 18, 11, 7. Si assuma che le collisioni siano gestite mediante indirizzamento aperto utilizzando come funzione di hash h(k), definita nel modo seguente: h(k,i) = (h0(k) + 3i + i^2) mod m h0(k) = k mod m Mostrare il contenuto della tabella al termine degli inserimenti e calcolare il numero medio di accessi alla tabella per la ricerca di una chiave presente nella tabella.

2 Esecuzione heapsort() Si specifichi, passo dopo passo, il contenuto dello heap eseguendo la procedura heapsort() per ordinare alfabeticamente gli 11 elementi: O, R, D, I, N, A, M, E, N, T, O. Sorgono difficolta dalla presenza di ` elementi con lo stesso valore?

3 Funzione heapsort() Si scriva una funzione per effettuare l’ordinamento dell’Heap

4 Grafi Leggere in input un grafo orientato G = (V, E) e rappresentarlo mediante liste di adiacenza.

Implementare una funzione che stampi tutti i vertici “sorgente” e tutti i vertici “pozzo” di G. Un vertice v ∈ V `e una sorgente se ha solo spigoli uscenti e nessuno spigolo entrante; `e un pozzo se ha solo spigoli entranti e nessuno spigolo uscente.

Si consideri il seguente grafo G orientato:

5 Visite Sia dato il grafo non orientato rappresentato dalla seguente lista di adiacenza:

A B C F G H B A I C A I D E F E D F G F A D E G A E H A I I B C H

se ne effettui la visita in profondità, considerando A come vertice sorgente, e si indichino per ogni vertice i tempi di inizio e fine visita.

Soluzioni 1 Inserimento in tabella hash La tabella hash è composta nel modo seguente: 0 1 2 3 4 5 6 7 8 9 10 33 23 24 14 11 16 13 18 31 10 Il valore 7 non può essere inserito, perché la funzione di scan scorre 11 posizioni (molte ripetute) e non trova l’unica cella libera rimasta (la 8). Dopo l’undicesimo tentativo il valori restituiti si ripetono. Il numero di accessi medi è 1:2 per i valori che hanno trovato collocazione.

m=11 | h(k,i)=(h0(k)+3i+i^2) mod m | h0(k) = k mod m | h(k,0)=(k mod m) mod m = k mod m = h0(k)

h(1,0)= 33 mod 11 = 0 t=1

0 1 2 3 4 5 6 7 8 9 10 33 - - - - - - - - - -

h(10,0)=10 mod 11 = 10 t=1

0 1 2 3 4 5 6 7 8 9 10 33 - - - - - - - - - 10

h(24,0)=24 mod 11 = 2 t=1

0 1 2 3 4 5 6 7 8 9 10 33 - 24 - - - - - - - 10

h(14,0)=14 mod 11 = 3 t=1

0 1 2 3 4 5 6 7 8 9 10 33 - 24 14 - - - - - - 10

h(16,0)=16 mod 11 = 5 t=1

0 1 2 3 4 5 6 7 8 9 10 33 - 24 14 - 16 - - - - 10

h(13,0)=13 mod 11 = 2 h(13,1)=(2+3*1+1^2) mod 11 = (2+3+1)mod 11 = 6 mod 11 = 6 t=2

0 1 2 3 4 5 6 7 8 9 10 33 - 24 14 - 16 13 - - - 10

h(23,0)=23 mod 11 = 1 t=1

0 1 2 3 4 5 6 7 8 9 10 33 23 24 14 - 16 13 - - - 10

h(31,0)=31 mod 11 = 9 t=1

0 1 2 3 4 5 6 7 8 9 10 33 23 24 14 - 16 13 - - 31 10

h(18,0)=18 mod 11 = 7 t=1

0 1 2 3 4 5 6 7 8 9 10 33 23 24 14 - 16 13 18 - 31 10

h(11,0)=11 mod 11 = 0 h(11,1)=(0+3*1+1^2) mod 11 = (0+3+1)mod 11 = 4 mod 11 = 4 t=2

0 1 2 3 4 5 6 7 8 9 10 33 23 24 14 11 16 13 18 - 31 10

h(7,0)=7 mod 11 = 7 h(7,1)=(7+3*1+1^2) mod 11 = (7+3+1)mod 11 = 11 mod 11 = 0 h(7,2)=(7+3*2+2^2) mod 11 = (7+6+4)mod 11 = 17 mod 11 = 6 h(7,3)=(7+3*3+3^2) mod 11 = (7+9+9)mod 11 = 25 mod 11 = 3 h(7,4)=(7+3*4+4^2) mod 11 = (7+12+16)mod 11 = 35 mod 11 = 2 h(7,5)=(7+3*5+5^2) mod 11 = (7+15+25)mod 11 = 47 mod 11 = 3 h(7,6)=(7+3*6+6^2) mod 11 = (7+18+36)mod 11 = 61 mod 11 = 6 h(7,7)=(7+3*7+7^2) mod 11 = (7+21+49)mod 11 = 77 mod 11 = 0 h(7,8)=(7+3*8+8^2) mod 11 = (7+24+64)mod 11 = 95 mod 11 = 7 h(7,9)=(7+3*9+9^2) mod 11 = (7+27+81)mod 11 = 115 mod 11 = 5 h(7,10)=(7+3*10+10^2) mod 11 = (7+30+100)mod 11 = 137 mod 11 = 4 h(7,11)=(7+3*11+11^2) mod 11 = (7+33+121)mod 11 = 161 mod 11 = 7 h(7,12)=(7+3*12+12^2) mod 11 = (7+36+144)mod 11 = 187 mod 11 = 0 h(7,13)=(7+3*13+13^2) mod 11 = (7+39+169)mod 11 = 215 mod 11 = 6 t-> infinito - impossibile collocare l'ultimo elemento

0 1 2 3 4 5 6 7 8 9 10 33 23 24 14 11 16 13 18 - 31 10

2.1 Esecuzione heapsort() Nella tabella successiva sono illustrati i vari passi dell’algoritmo. Nella prima colonna, lo stato del vettore ad ogni passo. Nella seconda colonna, l’operazione che ha portato il vettore in quello stato. La tabella e ulterioremente divisa in due righe; la prima rappresenta l’esecuzione di ` heapBuild(), mentre la seconda rappresenta lo spostamento dell’elemento massimo dello heap nella posizione corretta. Si noti che gli elementi che fanno effettivamente parte dello heap sono sottolineati; gli elementi non sottolineati sono elementi ordinati. Come e possibile vedere, elementi dello stesso valore non comportano ` difficolta.`

ORDINAMENTO Operazione Effettuata

01 02 03 04 05 06 07 08 09 10 11

O R D I N A M E N T O O R D I T A M E N N O HEAPify (h, 5) O R D N T A M E I N O HEAPify (h, 4) O R M N T A D E I N O HEAPify (h, 3) O T M N R A D E I N O HEAPify (h, 2) T R M N O A D E I N O HEAPify (h, 1) O R M N O A D E I N T A[1] ↔ A[11] R O M N O A D E I N T HEAPify (h, 1) N O M N O A D E I R T A[1] ↔ A[10] O O M N N A D E I R T HEAPify (h, 1) I O M N N A D E O R T A[1] ↔ A[9] O N M I N A D E O R T HEAPify (h, 1) E N M I N A D O O R T A[1] ↔ A[8] N N M I E A D O O R T HEAPify (h, 1) D N M I E A N O O R T A[1] ↔ A[7] N I M D E A N O O R T HEAPify (h, 1) A I M D E N N O O R T A[1] ↔ A[6] M I A D E N N O O R T HEAPify (h, 1) E I A D M N N O O R T A[1] ↔ A[5] I E A D M N N O O R T HEAPify (h, 1) D E A I M N N O O R T A[1] ↔ A[4] E D A I M N N O O R T HEAPify (h, 1) A D E I M N N O O R T A[1] ↔ A[3] D A E I M N N O O R T HEAPify (h, 1) A D E I M N N O O R T A[1] ↔ A[2]

1 2 3 4 5 6 7 8 9 10 11 O R D I N A M E N T O

O

R D

I N A M

E N T O

HEAPify (h, 5)

N T

T O => N O

O

R D

I T A M

E N N O

1 2 3 4 5 6 7 8 9 10 11 O R D I T A M E N N O

HEAPify (h, 4)

I N

E N => E I

O

R D

N T A M

E I N O

1 2 3 4 5 6 7 8 9 10 11

O R D N T A M E I N O

HEAPify (h, 3)

D M

A M => A D

O

R M

N T A D

E I N O

1 2 3 4 5 6 7 8 9 10 11

O R M N T A D E I N O

HEAPify (h, 2)

R T

N T => N R

O

T M

N R A D

E I N O

1 2 3 4 5 6 7 8 9 10 11

O T M N R A D E I N O

HEAPify (h, 1)

O T

T M => O M

O R

N R => N O

T

R M

N O A D

E I N O

1 2 3 4 5 6 7 8 9 10 11

T R M N O A D E I N O

Swap A[1] <-> A[11]

O

R M

N O A D

E I N T

1 2 3 4 5 6 7 8 9 10 11

O R M N O A D E I N T

3 Funzione heapsort()

void HEAPify(Heap h, int i) { int l, r, largest; l = LEFT(i); //indice del figlio sinistro r = RIGHT(i); //indice del figlio destro if ((l < h->heapsize) && (ITEMgreater(h->A[l], h->A[i])) ) // maggiore tra la radice ed il figlio sinistro

largest = l; else

largest = i; if ((r<h->heapsize)&& (ITEMgreater(h->A[r], h->A[largest]))) // maggiore tra la radice ed il figlio destro

largest = r; if (largest != i) { // se il maggiore non è la radice fa scambio col figlio il cui valore è maggiore

Swap(h, i,largest); HEAPify(h, largest); //avvia il controllo prendendo come radice il figlio di valore maggiore

} return;

}

void HEAPbuild (Heap h) { int i; for (i=(h->heapsize)/2-1; i >= 0; i--) //avvia il controllo prendendo come radice il figlio di valore maggiore

HEAPify(h, i); return;

}

void HEAPsort(Heap h) {

int i, j; HEAPbuild(h); j = h->heapsize; for (i = h->heapsize-1; i > 0; i--) {

Swap (h,0,i); h->heapsize--; HEAPify(h,0);

} h->heapsize = j; return;

}

4 Grafi 0 -> 1 1 NULL 2 -> 1 3 -> 2 4 -> 2 -> 3

Pozzo Vertice 1 Sorgente Vertice 4

#include <stdlib.h> #include <stdio.h> #define MAX 100

struct nodo { int info; struct nodo *next;

};

struct nodo *leggi_lista(void) { int a; struct nodo *p, *primo;

primo = NULL; scanf("%d", &a); while (a != -1) {

p = malloc(sizeof(struct nodo)); p->info = a; p->next = primo; primo = p; scanf("%d", &a);

} return(primo);

}

int leggi_grafo(struct nodo **l) { int i, n; printf("Numero di vertici: "); scanf("%d", &n); for (i=0; i<n; i++) {

printf("%d: ", i); *(l+i) = leggi_lista();

} return(n);

}

int *calcola_grado(struct nodo **l, int n) { int *m, i; struct nodo *p;

/* alloco dinamicamente una matrice m di n*2 interi */ m = malloc(sizeof (int)*2*n); if (m == NULL) {

printf("Errore: memoria insufficiente.\n"); exit(-1);

} /* azzero la matrice */ for (i=0; i<n; i++) {

*(m+i*2+0) = 0; *(m+i*2+1) = 0;

} /* scorro le liste di adiacenza di ogni vertice di G ed eseguo il calcolo. */ for (i=0; i<n; i++) {

p = *(l+i); while (p != NULL) {

/* incremento il numero di spigoli uscenti da i */ *(m+i*2) += 1;

/* p->info e’ adiacente ad i: incremento il numero di spigoli entranti in p->info. */

*(m + (p->info)*2 + 1) += 1; p = p->next;

} } return(m);

}

void pozzi_e_sorgenti(int *m, int n) { int i; printf("Sorgenti di G: "); for (i=0; i<n; i++) {

if (*(m+2*i+1) == 0) { printf("%d ", i);

} } printf("\nPozzi di G: "); for (i=0; i<n; i++) {

if (*(m+2*i) == 0) { printf("%d ", i);

} } printf("\n"); return;

}

int main(void) { struct nodo *liste[MAX]; int n, *matrice; n = leggi_grafo(&liste[0]); matrice = calcola_grado(&liste[0], n); pozzi_e_sorgenti(matrice, n); return(1);

}

5. Visite Di seguito l’albero DFS generato considerando A come vertice sorgente. Ciascun nodo sarà denotato con

n i/f dove n è il nome del vertice e i ed f sono i tempi di inizio e fine visita.

Appendice Algoritmo BFS per la visita in ampiezza di un grafo

/*

** bfs.c

**

** Implementazione dell'algoritmo BFS (Breadth First Search)

** per la visita in ampiezza di un grafo.

**

**

** Pseudo-codifica dell'algoritmo:

**

** per ogni vertice u di G diverso dalla sorgente s ripeti:

** colore(u) = bianco

** d(u) = infinito

** pi(u) = null

** end

**

** colore(s) = grigio

** d(s) = 0

** pi(s) = null

**

** Q = {s}

**

** fintanto che la coda Q non e` vuota ripeti:

** sia u il primo elemento estratto dalla coda Q

** per ogni vertice v adiacente ad u ripeti:

** se colore(v) = bianco allora

** colore(v) = grigio

** d(v) = d(u) + 1

** pi(v) = u

** aggiungi v alla coda Q

** end

** end

** colore(u) = nero

** end

**

** Marco Liverani (liverani@mat.uniroma3.it)

**

*/

/*

* inclusione delle librerie

*/

#include <stdlib.h>

#include <stdio.h>

/*

* definizione della costante che indica la massima dimensione

* del grafo (|V|<MAX).

*/

#define MAX 100

/*

* definizione della struttura utilizzata per rappresentare i

* vertici del grafo nelle liste di adiacenza ed i nodi della

* coda Q.

*/

struct nodo {

int info;

struct nodo *next;

};

/*

* Legge in input una sequenza di n interi e li memorizza su

* una lista. Restituisce il puntatore al primo elemento della lista.

*/

struct nodo *leggi_lista(void) {

struct nodo *p, *primo;

int x, n, i;

printf("Numero di elementi nella lista: ");

scanf("%d", &n);

primo = NULL;

for (i=0; i<n; i++) {

scanf("%d", &x);

p = malloc(sizeof(struct nodo));

p->info = x;

p->next = primo;

primo = p;

}

return(primo);

}

/*

* Legge in input le n liste di adiacenza (una per ogni

* vertice del grafo G). Restituisce il numero di vertici

* di cui e' costituito il grafo e l'array di puntatori

* ai primi elementi di ogni lista di adiacenza.

*/

int leggi_grafo(struct nodo *lista[]) {

int i, n;

printf("Numero di vertici: ");

scanf("%d", &n);

for (i=0; i<n; i++) {

printf("Lista di adiacenza del vertice %d.\n", i);

lista[i] = leggi_lista();

}

return(n);

}

/*

* accoda

*

* aggiunge un nodo alla coda Q; "primo" punta la primo elemento,

* "ultimo" punta all'ultimo elemento della coda.

*/

void accoda(struct nodo **primo, struct nodo **ultimo, int x) {

struct nodo *p;

p = malloc(sizeof(struct nodo));

p->info = x;

p->next = NULL;

if (*primo == NULL)

*primo = p;

if (*ultimo != NULL)

(*ultimo)->next = p;

*ultimo = p;

return;

}

/*

* estrai

*

* restituisce il primo elemento della coda e lo elimina dalla coda stessa.

*/

int estrai(struct nodo **primo, struct nodo **ultimo) {

int r;

if (*primo == NULL) {

r = -1;

} else {

r = (*primo)->info;

*primo = (*primo)->next;

}

return(r);

}

/*

* bfs

*

* visita in ampiezza del grafo rappresentato tramite le liste di

* adiacenza l[0], ..., l[n-1]; la visita parte dal vertice s.

*/

void bfs(struct nodo *l[], int n, int d[], int pi[], int s) {

struct nodo *primo, *ultimo, *v;

int colore[MAX], i, u;

primo = NULL;

ultimo = NULL;

for (i=0; i<n; i++) {

colore[i] = 0;

d[i] = -1;

pi[i] = -1;

}

colore[s] = 1;

d[s] = 0;

accoda(&primo, &ultimo, s);

while (primo != NULL) {

u = estrai(&primo, &ultimo);

v = l[u];

while (v != NULL) {

if (colore[v->info] == 0) {

colore[v->info] = 1;

d[v->info] = d[u] + 1;

pi[v->info] = u;

accoda(&primo, &ultimo, v->info);

}

v = v->next;

}

colore[u] = 2;

}

return;

}

/*

* Funzione principale.

*/

int main(void){

int i, n, d[MAX], pi[MAX], sorgente;

struct nodo *lista[MAX];

n = leggi_grafo(lista);

printf("Sorgente della visita: ");

scanf("%d", &sorgente);

bfs(lista, n, d, pi, sorgente);

for (i=0; i<n; i++) {

printf("Vertice %d: padre=%d, distanza=%d\n", i, pi [i], d[i]);

}

return(0);

}

Algoritmo DFS per la visita in profondità di un grafo

/*

** dfs.c

**

** Letto in input un grafo orientato, rappresentarlo

** mediante liste di adiacenza. Esegue la visita in

** profondita' del grafo mediante l'algoritmo DFS

** (Depth First Search).

**

** Pseudo-codifica dell'algoritmo:

**

** DFS(G)

** per ogni vertice u di V(G) ripeti:

** colore(u) = bianco

** padre(u) = NULL

** per ogni vertice u di V(G) ripeti:

** se colore(u)=bianco allora VISITA(G, u)

** End

**

** VISITA(G, u)

** colore(u) = grigio

** per ogni vertice v adiacente ad u ripeti:

** se colore(v)=bianco allora:

** padre(v) = u

** VISITA(G, v)

** colore(u) = nero

** End

**

** Marco Liverani (liverani@mat.uniroma3.it) - Maggio 2001

**

*/

/*

* inclusione delle librerie

*/

#include <stdlib.h>

#include <stdio.h>

/*

* definizione della costante che indica la massima dimensione

* del grafo (|V|<MAX).

*/

#define MAX 100

/*

* definizione della struttura utilizzata per rappresentare i

* vertici del grafo nelle liste di adiacenza.

*/

struct nodo {

int info;

struct nodo *next;

};

/*

* Legge in input una sequenza di n interi e li memorizza su

* una lista. Restituisce il puntatore al primo elemento della lista.

*/

struct nodo *leggi_lista(void) {

struct nodo *p, *primo;

int x, n, i;

printf("Numero di elementi nella lista: ");

scanf("%d", &n);

primo = NULL;

for (i=0; i<n; i++) {

scanf("%d", &x);

p = malloc(sizeof(struct nodo));

p->info = x;

p->next = primo;

primo = p;

}

return(primo);

}

/*

* Legge in input le n liste di adiacenza (una per ogni

* vertice del grafo G). Restituisce il numero di vertici

* di cui e' costituito il grafo e l'array di puntatori

* ai primi elementi di ogni lista di adiacenza.

*/

int leggi_grafo(struct nodo *lista[]) {

int i, n;

printf("Numero di vertici: ");

scanf("%d", &n);

for (i=0; i<n; i++) {

printf("Lista di adiacenza del vertice %d.\n", i);

lista[i] = leggi_lista();

}

return(n);

}

/*

* Visita il grafo G a partire dal vertice u, con un algoritmo

* ricorsivo.

*/

void visita(int u, struct nodo *l[], int colore[], int pi []) {

struct nodo *p;

colore[u] = 1;

p = l[u];

while (p != NULL) {

if (colore[p->info] == 0) {

pi[p->info] = u;

visita(p->info, l, colore, pi);

}

p = p->next;

}

return;

non sono stati rilasciati commenti
Questa è solo un'anteprima
3 pagine mostrate su 27 totali