140
Appunti di 02MNONZ - Algoritmi e Programmazione 1 Studente: MACI Samuele Politecnico di Torino Anno Accademico 2011/2012 [email protected] Docente: CAMURATI Paolo Enrico Preside III Facolt`a - Torino [email protected] Docente: CABODI Giampiero Prof. Associato Confermato [email protected] Docente: NOCCO Sergio Collaboratori coordinati e continuativi Collaborazione scientifica per ricerche [email protected] Ultima revisione: 16 marzo 2012 1 Il presente quaderno di appunti e stato redatto completamente con l’applicativo T E XnicCenter

Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

  • Upload
    lykhue

  • View
    289

  • Download
    14

Embed Size (px)

Citation preview

Page 1: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Appunti di 02MNONZ - Algoritmi e Programmazione1

Studente: MACI SamuelePolitecnico di Torino

Anno Accademico 2011/2012

[email protected]

Docente: CAMURATI Paolo Enrico

Preside III Facolta - Torino

[email protected]

Docente: CABODI Giampiero

Prof. Associato Confermato

[email protected]

Docente: NOCCO Sergio

Collaboratori coordinati e continuativi

Collaborazione scientifica per ricerche

[email protected]

Ultima revisione: 16 marzo 2012

1Il presente quaderno di appunti e stato redatto completamente con l’applicativo TEXnicCenter

Page 2: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518
Page 3: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Indice

I Teoria 3

1 Gli Algortmi 51.1 Problemi Decisionali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

1.1.1 Problemi trattabili/intrattabili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51.2 Ricerche su i vettori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.2.1 Ricerca lineare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.2.2 Ricerca binaria o dicotomica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.3 Algoritmi di ordinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71.3.1 Classificazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71.3.2 Insertion Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81.3.3 Bubble Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91.3.4 Selection Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101.3.5 Counting Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

1.4 Analisi della complessita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121.4.1 Classificazione degli algoritmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121.4.2 Analisi asintotica di capo peggiore . . . . . . . . . . . . . . . . . . . . . . . . . . . 121.4.3 Notazione asintotica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

1.5 Online Connectivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131.5.1 Quick Find . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141.5.2 Quick Union . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

1.6 Matematica discreta: grafi e alberi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151.6.1 Grafo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151.6.2 Incidenza e adiacenza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161.6.3 Grado di un vertice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171.6.4 Cammini e raggiungibilita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171.6.5 Connessione nei grafi non orientati . . . . . . . . . . . . . . . . . . . . . . . . . . . 171.6.6 Connessione nei grafi orientati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181.6.7 Grafi densi o sparsi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181.6.8 Grafo pesato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181.6.9 Alberi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

1.7 La ricorsione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201.7.1 Paradigma Divide et Impera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221.7.2 Analisi di complessita di alcuni algoritmi . . . . . . . . . . . . . . . . . . . . . . . 251.7.3 Torri di Hanoi, gioco matematico risolto con il dividi et impera . . . . . . . . . . . 261.7.4 Backtracking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

1.8 ADT: Heap, code a priorita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271.8.1 Procedura di insert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281.8.2 Procedura di heapify . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281.8.3 Procedura di BuildHeap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291.8.4 HeapSort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

1.9 ADT: Tabella di simboli (Symbol Table) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301.9.1 Operazioni di un ADT SystemTable . . . . . . . . . . . . . . . . . . . . . . . . . . 301.9.2 Strutture dati di un ADT SystemTable . . . . . . . . . . . . . . . . . . . . . . . . 301.9.3 Ricerca in un ADT SystemTable . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

1.10 Alberi binari di ricerca (BST) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311.10.1 Operazioni in un BST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321.10.2 Complessita in un BST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321.10.3 Operazioni utili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321.10.4 Implementazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

I

Page 4: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

II Programmazione 35

2 Problem Solving elementare 37

2.1 Problem Solving elementare su dati scalari . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

2.1.1 Problem Solving e algoritmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

2.1.2 Strategie di soluzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

2.1.3 Classificazione dei problemi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

3 Puntatori e allocazione dinamica 45

3.1 Tipo di dato puntatore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

3.1.1 Puntatore come riferimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

3.2 Definizione e operazione sui puntatori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

3.2.1 Definizione di un puntatore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

3.2.2 Variabili e operazioni sui puntatori . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

3.2.3 Confronto tra puntatori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

3.2.4 Aritmetica dei puntatori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

3.3 Implementazioni di strlen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

3.4 Pasaggio parametri by reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

3.4.1 Vettore come parametro di una funzione . . . . . . . . . . . . . . . . . . . . . . . . 48

3.5 Puntatori a strutture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

3.5.1 Strutture ricorsive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

3.6 Allocazione dinamica della memoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

3.6.1 Malloc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

3.7 Strutture Astratte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

3.7.1 Liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

III Laboratorio 53

4 Esercitazione 1 55

4.1 Esercizio n. 1: manipolazione di una matrice - I . . . . . . . . . . . . . . . . . . . . . . . . 55

4.2 Esercizio n. 2 - Manipolazione di una matrice - II . . . . . . . . . . . . . . . . . . . . . . . 57

4.3 Esercizio n. 3: riformattazione di un testo . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

5 Esercitazione 2 63

5.1 Esercizio n. 1: decompressione di un testo . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

5.2 Esercizio n. 2: stringhe periodiche. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

5.3 Esercizio n. 3: voli aerei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

6 Esercitazione 3 69

6.1 Esercizio n. 1: confronto tra algoritmi di ordinamento . . . . . . . . . . . . . . . . . . . . 69

6.2 Esercizio n. 2: ordinamento di stringhe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

7 Esercitazione 4 75

7.1 Esercizio n. 1: occorrenze di parole . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

7.2 Esercizio n. 2: indice analitico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

7.3 Esercizio n. 3: prodotto di matrici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

8 Esercitazione 5 83

8.1 Esercizio n. 1: Generazione di numeri binari. . . . . . . . . . . . . . . . . . . . . . . . . . 83

8.2 Esercizio n. 2: Sviluppo di un sistema del totocalcio. . . . . . . . . . . . . . . . . . . . . . 84

8.3 Esercizio n. 3: calcolo del determinante di una matrice. . . . . . . . . . . . . . . . . . . . 85

9 Esercitazione 6 89

9.1 Esercizio n. 1: Punti del piano. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

9.2 Esercizio n. 2: Ricerche dicotomiche. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

9.3 Esercizio n. 3: Confronto tra algoritmi di ordinamento. . . . . . . . . . . . . . . . . . . . 97

10 Esercitazione 7 103

10.1 Esercizio n. 1: gestione di strutture FIFO. . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

10.2 Esercizio n. 2: gestione di strutture LIFO. . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

II

Page 5: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

11 Esercitazione 8 11711.1 Esercizio n. 1: gestione di una coda prioritaria - I . . . . . . . . . . . . . . . . . . . . . . . 11711.2 Esercizio n. 2: gestione di una coda prioritaria - II . . . . . . . . . . . . . . . . . . . . . . 126

III

Page 6: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

IV

Page 7: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Elenco dei Sorgenti

1.1 Ricerca lineare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.2 Ricerca binaria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.3 InsertionSort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81.4 BubbleSort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91.5 BubbleSort ottimizzato con flag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91.6 SelectionSort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101.7 CountingSort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111.8 Quick Find . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141.9 Quick Union . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151.10 Fattoriale ricorsivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201.11 Fibonacci ricorsivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201.12 Massimo comun divisore ricorsivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201.13 Valutazione di espressioni notazione polacca . . . . . . . . . . . . . . . . . . . . . . . . . . 211.14 Ricerca binaria ricorsiva . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211.15 Massimo di un vettore ricorsivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211.16 Mergesort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231.17 Quick Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241.18 Torri di Hanoi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271.19 Procedura di insert in un heap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281.20 Procedura di heapify in un heap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292.1 Calcolo della ridotta n-esima di una serie armonica . . . . . . . . . . . . . . . . . . . . . . 382.2 Visualizzazione della codifica binaria di un intero . . . . . . . . . . . . . . . . . . . . . . . 392.3 Conversione da base b0 a base b1 (iterativo) . . . . . . . . . . . . . . . . . . . . . . . . . . 392.4 Codifica di un file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402.5 Grafico di una parabola su una interfaccia a carattere . . . . . . . . . . . . . . . . . . . . 412.6 Riformattazione testi − mediante sottostringhe . . . . . . . . . . . . . . . . . . . . . . . . 422.7 Verifica ordine alfabetico file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433.1 Esempio di uso di void* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463.2 Aritmetica dei puntatori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463.3 strlen - I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473.4 strlen - II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473.5 strlen - III . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473.6 strlen - IV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473.7 Vettore come parametro di una funzione - I . . . . . . . . . . . . . . . . . . . . . . . . . . 483.8 Vettore come parametro di una funzione - II . . . . . . . . . . . . . . . . . . . . . . . . . . 483.9 strcmp - I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483.10 strcmp - II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483.11 strncmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493.12 strstr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493.13 Esempio Struttura ricorsiva . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503.14 Esempio di Giuseppe Flavio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503.15 Prototipo malloc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514.1 Manipolazione di una matrice - I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554.2 Manipolazione di una matrice - II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574.3 Manipolazione di una matrice - III . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594.4 Riformattazione di un testo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615.1 Decompressione di un testo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 635.2 Stringhe periodiche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645.3 Voli aerei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666.1 Confronto degli algoritmi di ordinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . 696.2 Ordinamento di stringhe con allocazione statica . . . . . . . . . . . . . . . . . . . . . . . . 72

V

Page 8: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

6.3 Ordinamento di stringhe con allocazione dinamica . . . . . . . . . . . . . . . . . . . . . . 737.1 Occorrenza di parole . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 757.2 Occorrenze parole con indice analitico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 777.3 Prodotto di matrici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 798.1 Generazione di numeri binari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 838.2 Sviluppo di un sistema del totocalcio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 848.3 Determinante di una matrice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 869.1 Punti del piano (client.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 899.2 Punti del piano (point.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 939.3 Punti del piano (point.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 939.4 Ricerche dicotomiche (client.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 949.5 Ricerche dicotomiche (item.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 969.6 Ricerche dicotomiche (item.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 969.7 Confronto tra algoritmi di ordinamento (client.c) . . . . . . . . . . . . . . . . . . . . . . . 979.8 Confronto tra algoritmi di ordinamento (item.h) . . . . . . . . . . . . . . . . . . . . . . . 989.9 Confronto tra algoritmi di ordinamento (item.c) . . . . . . . . . . . . . . . . . . . . . . . . 999.10 Confronto tra algoritmi di ordinamento (sort.h) . . . . . . . . . . . . . . . . . . . . . . . . 999.11 Confronto tra algoritmi di ordinamento (sort.c) . . . . . . . . . . . . . . . . . . . . . . . . 10010.1 Queue (client.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10310.2 Queue (item.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10610.3 Queue (item.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10610.4 Queue (queue.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10610.5 Queue (queue.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10710.6 Queue (queue.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10810.7 Queue (queue.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10810.8 Stack (client.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11010.9 Stack (item.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11210.10Stack (item.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11310.11Stack (stack.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11310.12Stack (stack.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11310.13Stack (stack.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11510.14Stack (stack.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11511.1 Coda prioritaria - I (client.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11711.2 Coda prioritaria - I (job.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11911.3 Coda prioritaria - I (job.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11911.4 Coda prioritaria - I (ITEM.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12011.5 Coda prioritaria - I (ITEM.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12111.6 Coda prioritaria - I (HEAP.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12111.7 Coda prioritaria - I (HEAP.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12111.8 Coda prioritaria - I (PriorityQueue.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12311.9 Coda prioritaria - I (PriorityQueue.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12311.10Coda prioritaria - I (LIST.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12311.11Coda prioritaria - I (LIST.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12411.12Coda prioritaria - I (PriorityQueue.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12511.13Coda prioritaria - I (PriorityQueue.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12511.14Coda prioritaria - II (client.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12611.15Coda prioritaria - II (Hour.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12911.16Coda prioritaria - II (Hour.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12911.17Coda prioritaria - II (job.h) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13011.18Coda prioritaria - II (job.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

Page 9: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Presentazione

Il corso e tenuto dal Prof. Paolo Enrico Camurati, Prof. Giampiero Cabodi e dal Prof. Sergio Nocco.I laboratori inizieranno nella settimana del 10 ottobre 2011 e sono nelle date:

Squadra 1 Giovedı dalle ore 14:30 alle ore 16:00Squadra 2 Giovedı dalle ore 16:00 alle ore 15:30Squadra 3 Venerdı dalle ore 11:30 alle ore 13:00Squadra 4 Venerdı dalle ore 13:00 alle ore 14:30

I testi consigliati sono:

• Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

• Deitel & Deitel, Corso completo di programmazione in C, Apogeo, ISBN 8850326335

L’esame consiste in due parti, scritto e orale. Lo scritto comprendera una parte teorica (12 punti) e unaparte di programmazione (18 punti). Durante lo scritto sara possibile consultare manuali di C come ilDeitel & Deitel oppure il Kernighan & Ritchie, inoltre, al termine dello scritto bisogna portar copia delprograma per correggerlo e inviarlo corretto al docente responsabile del corso. Il voto dell’esame oralenon fara media in quanto sara gia comprensivo della valutazione dello scritto.Per consulenze non sono previsti degli orari esatti, ma basta mandare una mail e sara fissato un appun-tamento.

1

Page 10: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

2

Page 11: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Parte I

Teoria

3

Page 12: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518
Page 13: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Capitolo 1

Gli Algortmi

Un algoritmo e come una ricetta, e composto da una sequenza finita di istruzioni elementari.L’algoritmo ha l’obiettivo di risolvere un problema partendo dai dati di input, ottenendo quindi i dati dioutput.Ogni singola istruzione ha un suo significato, che non puo variare in seguito.Un algoritmo, per sua definizione, deve avere un limite superiore, e certo quindi che un algoritmo abbiauna terminazione (anche se non in tempi accettabili).Si usano gli algoritmi per essere portati all’interno di elaboratori elettronici, in modo da poter aumentarela velocita e quindi poter anche aumentare la mole di dati da poter trattare in tempi ragionevoli.Un super-computer comunque non puo sostituire un buon algoritmo.

1.1 Problemi Decisionali

I problemi decisionali sono dei problemi che ammettono una risposta binaria, una risposta del tipo SI/-NO.Vi sono anche dei problemi di ottimizzazione, problemi in cui ogni soluzione e una funzione di costo ebisogna fornire solo la risposta la cui funzione di costo e minima.Un problema si dice decidibile se esiste un algoritmo che li risolve.Vi sono anche problemi definiti come indecidibili se non vi e un algoritmo che li risolve.Turing, nel 1937, concettualizzo il problema della terminazione di un algoritmo, egli sostiene che nonsi puo sapere se con un algoritmo arbitrario e dei dati arbitrari l’algoritmo termina. (ad esempio laCongettura di Goldbach).

1.1.1 Problemi trattabili/intrattabili

I problemi risolvibili possono essere:

• trattabili, e possibile limitare superiormente l’algoritmo se esiste un algoritmo di tipo polinomiale(con complessita polinomiale).Un algoritmo polinomiale e un algoritmo che, operando su n dati, data una costante c > 0, terminiin un numero massimo di passi a nc.Teoricamente sono trattabili algoritmi algoritmi polinomiali con n100 passi, praticamente gli algorit-mi polinomiali con c > 4 non sono risolubili in tempi ragionevoli. I problemi che hanno un’algoritmodi tipo polinomiale si dicono di classe P.

• Vi sono problemi dedicibili definiti come intrattabili, in quanto sono risolubili con algoritmi polino-miali. Esempi possono essere quelli con complessita esponenziale (come le Torri di Hanoi).Esistono problemi per cui si conosce il solo algoritmo esponenziale, ma non e mai stato dimostratoche non esiste un algoritmo polinomiale.

• Si chiama classe NP la classe di problemi che hanno una verifica di tipo polinomiale ma una risolu-zione di tipo non polinomiale (potrebbe anche esistere un algoritmo di tipo polinomiale ma ancoranon e stato dimostrato che non esiste).P ⊆ NP per definizione, ma e possibile che P coincide con NP , e probabile che vi siano problemiNP che non sono P .

5

Page 14: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Esiste un sottoinsieme di NP denominato come NP-Completo, tali che con una serie di trasforma-zioni si risolvono in modo polinomaile.Durante il corso si tratteranno solo problemi di classe P .

1.2 Ricerche su i vettori

1.2.1 Ricerca lineare

Vi e un metodo generale, la ricerca sequenziale/lineare. Tale algoritmo ha un array di dimenzione n, e loscansioniamo dall’indice 0 all’indice n− 1.La ricerca termina in due condizioni:

• se l’elemento viene trovato viene ritornato l’indice i ∈ [0, n− 1]

• se l’elemento non viene trovato viene ritornato un elemento sentinella, che non puo essere un indicei /∈ [0, n− 1] (generalmente −1).

successo

caso migliore 1 accessocaso peggiore n accessicaso medio n

2 accessiinsuccesso n accessi

Bisogna carattarizzare l’algoritmo con la sua complessita

nel caso peggiore (una stima conservativa).1 int ricercaSequenziale(int v[], int l, int r, int k)

//l = estremo sinistro , r = estremo destro , k = chiave

3

int i=l;

5 while(i<r && k!=v[i])

i++;

7 if(i==r)

return -1;

9 return i;

Listing 1.1: Ricerca lineare

1.2.2 Ricerca binaria o dicotomica

Si puo effettuare solo su array ordinati per una chiave, che deve essere quella sulla quale si effettua laricerca.Si confronta k, l’elemento da cercare, con l’elemento centrale dell’array, se l’elemento concide si termina,altrimenti se la chiave e superiore all’elemento centrale si effettua la ricerca dicotomica nel sottovettoredestro, mentre se la chiave e inferiore all’elemento centrale si effettua la ricerca dicotomica nel sottovettoresinistro. Si termina nel caso in cui l’eleento viene trovato, o nel caso l’array su cui si effettua la ricercacontiene solo un elemento e non e l’elemento ricercato. Questo algoritmo divide l problema in meta adogni passo, quindi si deduce che quest’algoritmo e di tipo logaritmico.int ricerca_binaria(int v[], int l, int r, int k)

2

int c;

4 while(c<=b)

6 c = (a+b)/2;

if(v[c]==k)

8 return c;

else if(v[c]<k)

10 a=c+1;

else

12 b = c-1;

14 return -1;

6

Page 15: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Listing 1.2: Ricerca binaria

1.3 Algoritmi di ordinamento

Sono algoritmi che preso un vettore come parametro di input lo ordinano, secondo una determinatarelazione d’ordine. In generale gli elementi che cercheremo di ordinare saranno dei record/strutture didati, nei quali dovra essere definita una chiave di ordinamento e potrebbero essere definiti dei nuovi datisatellite (non influenti sull’ordinamento).

1.3.1 Classificazione

Gli algoritmi di ordinamento possono essere classificati secondo metodo diversi:

ordinamento interno se i dati da ordinare sono tutti in memoria centrale, ha accesso diretto ai dati

ordinamento esterno si i dati da ordinare sono, anche non tutti, in memoria esterna (memoria dimassa), ha accesso sequenziale ai dati

ordinamento in loco se per l’ordinamento oltre al vettore saranno necessarie una quantita finita dimemoria che e indipendente dalla dimensione del vettore

ordinamento non in loco se per l’ordinamento saranno necessarie delle locazioni di memoria e talequantita e dipendente dalla dimensione del vettore

ordinamento stabile se in fase di ordinamento se sono presenti piu elementi con medesima chiave essisaranno ordinati ma resteranno con lo stesso ordine con cui erano nel vettore

in base alla complessita :

• O(n2) sono gli algoritmi di ordinamento piu semplici, iterativi e basati sul confrontoesempio di algoritmi di questa classe e Insersion Sort, Selection Sort, Exchange/Bubble Sort

• O(n32 ) un esempio di questo tipo e lo ShellSort (non verra considerato nel seguito del corso)

• O(n · log(n)) sono gli algoritmi di ordinamento piu complessi, ricorsivi e basati sul confrontoesempio di algoritmi di questa classe e Merge Sort, Quick Sort e Heap Sort

• O(n) sono algoritmi di ordinamento non basati sul confronto, sono applicabili solo con delleipotesi molto restrittive, sono basati sul calcoloesempio di algoritmi di questa classe e Counting Sort, Radix Sort, Bin/Bucket Sort

Gli algoritmo di ordinamento con complessita O(n·log(n)) sono gli algoritmi di ordinamento migliorinel caso in cui sia necessario il confronto, mentre la migliore complessita si ha con complessita O(n)ma sono poco utilizzabili perche richiedono delle ipotesi troppo restrittive.

Dimostrazione 1 (Limite inferiore di complessita negli algoritmi basati sul confronto) Un al-goritmo di ordinamento basato sul confronto ha come operazione elementare il confronto tra ai e aj, saranecessario quindi decidere se ai < aj e ai ≥ aj.Se volessi rappresentare le decisioni in modo grafico si avrebbe la realizzazione di un albero delle decisioni(che e un albero binario). Se volessi trovare l’ordinamento dei seguenti elementi a1, a2, a3 (supponendodi conoscere le relazioni tra gli elementi) avrei la realizzazione del seguente albero decisionale

<=

<=

<= <=

<=

>

>

> >

>

a1:a2

a2:a3

a1:a3

a1:a3

a2:a3a1:a2:a3

a1:a3:a2 a3:a1:a2 a2:a3:a1

a2:a1:a3

a3:a2:a1

7

Page 16: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Nel caso di n dati da ordinare tutte le possibili condizioni di uscita sono tutte le permutazioni che sipossono realizzare con n elementi, cioe n!. Se contassimo il numero di confronti che ci sono tra la radicee la foglia (permutazione corretta) tale valore e sempre uguale al numero di archi che separano la radicedalla foglia.Poiche un albero decisionale e un albero binario, si puo supporre che l’albero decisionale sia un alberobinario completo nel quale tutte le permutazioni si possono trovare solo sulle foglie. Detta h l’altezzamassima dell’arco si possono avere al massimo 2n foglie, ma abbiamo supposto che le permutazioni devonoessere sulle foglie, pertanto sara necessario avere un numero di foglie pari ad almento n!. Si ha quindi

n! ≤ 2h

Utilizzando ora la maggiorazione di Stirling

n! >(ne

)nn→ +∞

Si ha quindi

2h ≥ n! >(ne

)n⇒ log2(2n) > log2

[(ne

)n]h > n · log2

(ne

)= n · log2 n− n · log2 e

Poiche n · log2 n−n · log2 e ∼ n · log2 n per n→ +∞ allora h > n · log2 n. Si ha quindi che la complessitah sara sempre maggiore a n · log n, quindi e limitata inferiormente

T (n) = Ω(n · log n)

Si tralascia la base del logaritmo, in quanto il cambio di base necessita solo di una moltiplicazione peruna costante e quindi ininfluente al caso asintotico.

1.3.2 Insertion Sort

Si ha in input un vettore potenzialmente senza relazione d’ordine (ovviamente contenente elementi chepossono avere una certa relazione d’ordine).Si porta in output il vettore ordinato secondo una determinata relazione d’ordine (si ottiene permutangogli elementi di partenza).Il funzionamento e abbastanza semplice e rudimentale. Si introduce nel vettore il primo elemento, siintroduce il secondo inserendolo nella giusta relazione d’ordine rispetto agli altri elementi (eventualmentetraslando tutti gli elementi gia presenti). Questo algoritmo ha nel caso migliore n operazioni mentre nelcaso peggiore n2 operazioni.Questo algoritmo ha un approccio incrementale, in quanto il sottovettore ordinato si espande.Si termina l’algoritmo quando il sottovettore ordinato ha dimensione uguale a quella del vettore.

1 void InsertionSort(int A[], int n)

3 int i, j, x;

for(i=1; i<n; i++)

5

x = A[i];

7 j = i - 1;

while (j >= 0 && x < A[j])

9

A[j+1] = A[j];

11 j--;

13 A[j+1] = x;

15 Listing 1.3: InsertionSort

8

Page 17: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

1.3.3 Bubble Sort

E un ordinamento che privilegia la posizionazione corretta veloce dei valori alti.Come struttura dati di ingresso necessita un vettore.Tale algoritmo ha un approccio incrementale, pertanto il vettore concettualmente sara suddiviso in duesottovettori:

• sottovettore sinistro, che contiene gli elementi ancora da ordinare, inizialmente coincide con ilvettore in ingresso

• sottovettore destro, contiene gli elementi gia ordinati, inizialmente e vuoto

Si ha la terminazione dell’algoritmo nel caso in cui il sottovettore destro coincide con il vettore di ingresso,dato cio che e stato fin’ora esplicitato sarebbe necessario effettuare confronti per n − 1 elementi, doven e la dimensione del vettore, e possible anche cercare di ottimizzarlo facendo evitare dei controlli sesono certamente inutili, una buona ottimizzazione si puo avere aggiungendo un flag che mi indica se cisono stati scambi; se alla fine dell’iterazione non sono avvenuti scambi allora significa che il vettore e giaordinato e quindi si puo terminare precocemente l’ordinamento.

1 void bubble_sort(int A[], int n)

3 int i, j, temp;

for(i=0; i<n-1; i++)

5

for(j=0; j<n-1-i; j++)

7

if(A[j]>A[j+1])

9

temp = A[j];

11 A[j] = A[j+1];

A[j+1] = temp;

13

15

Listing 1.4: BubbleSort

void opt_bubble_sort(int A[], int n)

2

int i, j, temp , fine;

4 fine = 0;

for(i=0; i<n-1 && !fine; i++)

6

fine =1;

8 for(j=0; j<n-1-i; j++)

10 if(A[j]>A[j+1])

12 temp = A[j];

A[j] = A[j+1];

14 A[j+1] = temp;

fine =0;

16

18

Listing 1.5: BubbleSort ottimizzato con flag

La versione ottimizzata potra dei miglioramenti nel caso medio, ma la complessita asintotica di casopeggiore resta invariata.

9

Page 18: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Analisi asintotica L’algoritmo e composto da confronti, di costo unitario, e da due cicli:

• ciclo esterno eseguito (n− 1) volte

• ciclo interno viene eseguito, all’i-esima iterazione, (n− 1− i) volte

Pertanto

T (n) = (n− 1) + (n− 2) + . . .+ 2 + 1 =n2

2= O(n2)

Caratteristiche e un algoritmo di ordinamento stabile e in loco.

1.3.4 Selection Sort

L’algoritmo consiste nella ricerca del minimo valore presente nel vettore e posizionarlo nella prima posi-zione, cercare il secondo minimo e metterlo nella seconda posizione e cosı via, il procedimento va eseguiton volte se n e la dimensione del vettore.Come struttura dati di ingresso necessita un vettore. Tale algoritmo ha un approccio incrementale,pertanto il vettore concettualmente sara suddiviso in due sottovettori:

• sottovettore sinistro, che contiene gli elementi ordinati, inizialmente e vuoto

• sottovettore destro, contiene gli elementi da ordinare, inizialmente coincide con il vettore in ingresso

Si ha la terminazione dell’algoritmo nel caso in cui il sottovettore sinistro coincide con il vettore diingresso.

1 void selection_sort(int A[], int l, int r)

3 int i, j, temp , min;

for(i=l; i<r; i++)

5

min=i;

7 for(j=i+1; j<=r; j++)

9 if(A[j]<A[min])

min=j;

11

temp = A[i];

13 A[i] = A[min];

A[min] = temp;

15

Listing 1.6: SelectionSort

Analisi asintotica L’algoritmo e composto da confronti, di costo unitario, e da due cicli:

• ciclo esterno eseguito (n− 1) volte

• ciclo interno viene eseguito, all’i-esima iterazione, (n− 1− i) volte

Pertanto

T (n) = (n− 1) + (n− 2) + . . .+ 2 + 1 =n2

2= O(n2)

Caratteristiche e un algoritmo di ordinamento stabile e in loco.

1.3.5 Counting Sort

E un algoritmo di ordinamento non basato sul confronto ma basato sul calcolo.Intuitivamente l’algoritmo cerca di determinare il quanti elementi vanno messi prima di un determinatoelemento, pertanto verra assegnata direttamente all’elemento la posizione corretta (per poter avere allafine l’ordinamento).Tale algoritmo e molto utile in presenza di chiavi ripetute, in quanto altrimenti si avrebbe un uso eccessivodella memoria (sarebbe utile anche che le chiavi fossero vicine per evitare che ci sia memoria inutilizzata).Occorre innanzitutto conoscere l’ampiezza dell’intervallo entro il quale va fatto l’ordinamento, occorrecioe conoscere l’elemento minimo e l’elemento massimo.

10

Page 19: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

/**

2 * A e il vettore da ordinare , n e la sua dimensione

**/

4 int min , max , i;

min = max = A[0];

6 for(i=1; i<n; i++)

8 if(A[i]<min)

min = A[i];

10 else if(A[i]>max)

max = A[i];

12 Ora e necessario realizzare il vettore delle occorrenze semplici (un vettore che nell’indice contiene il valoredella chiave e come contenuto contiene il numero delle sue occorrenze). Sara necessario inizializzarloinizialmente a 0./**

2 * il vettore occ sara allocato in qualche modo e avra dimensione pari

* a max -min+1

4 **/

int i;

6 for(i=0; i<=max -min; i++)

occ[i]=0;

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

occ[A[i]-min ]++; Ora e necesario calcolare il vettore delle occorrenze multiple, cioe il vettore delle occorrenze dove inposizione i-esima vi e il numero di occorrenze di tutti gli elementi precedenti

1 /**

* il vettore occ sara allocato in qualche modo e avra dimensione pari

3 * a max -min+1

**/

5 int i;

for(i=1; i<n; i++)

7 occ[i]+= occ[i-1]; Per ottenere finalmente il vettore di uscita si percorre il vettore di ingresso in senso inverso (da n − 1 a0).

1 /**

* il vettore out sara allocato in qualche modo e avra dimensione pari

a n

3 **/

int i;

5 for(i=n-1; i>=0; i--)

out[(occ[A[i]]--)-min]=A[i]; int* counting_sort(int A[], int n)

2

int i, min , max , *occ , *out;

4 min = max = A[0];

for(i=1; i<n; i++)

6

if(A[i]<min)

8 min = A[i];

else if(A[i]>max)

10 max = A[i];

12 occ = (int*) calloc(max -min+1, sizeof(int));

//l’uso di calloc ci assicura di avere la memoria inizializzata a 0

11

Page 20: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

14 out = (int*) malloc(sizeof(int)*n);

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

16 occ[A[i]-min ]++;

for(i=1; i<n; i++)

18 occ[i]+=occ[i-1];

for(i=n-1; i>=0; i--)

20 out[(occ[A[i]]--)-min]=A[i];

return out;

22 Listing 1.7: CountingSort

1.4 Analisi della complessita

Nella stesura di un buon algoritmo bisogna anche cercare di prevedere la memoria1 e il tempo che vieneutilizzato dall’algoritmo.La previsione del tempo non consiste nell’immaginare il tempo impiegato in secondi, ma giudicare il temponecessario proporzionale al numero di passi e/o operazioni che bisogna svolgere. Per tale previsione enecessario sapere la dimensione del problema, i dati specifici non sono influenti in quanto si fanno sempreprevisioni conservative.

S(n) → spazio occupato in memoriaT (n) → tempo di esecuzione

1.4.1 Classificazione degli algoritmi

Gli algoritmi si classificano in:

1 costantelog n logaritmicon lineare

n · log n linearitmicon2 quadraticon3 cubico2n esponenziale

1.4.2 Analisi asintotica di capo peggiore

Si effettua una stima del limite superiore di T (n). Sarebbe necessario effettuare una stima per dimensionimolto grandi (n → +∞), inoltre si sceglie il caso peggiore in quanto non sara mai possibile trovare casipeggiori a quello che e stato esaminato nell’analisi asintotica (stima conservativa).Si cerca di avere una complessita minima possibile in quanto un buon algoritmo puo compensare unhardware poco prestante.

Esempio 1 (Analisi asintotica nella ricerca lineare) Poiche in una ricerca il caso peggiore si haquando non viene trovata la chiave. Poiche abbiamo esaminato precedentemente tale tipo di ricerca esi e osservato che si effettuano al massimo n passi, pertanto l’algoritmo e cresce linearmente con ladimensione dei dati.

Esempio 2 (Analisi asintotica nella ricerca dicotomica) Analisi:

• All’inizio della ricerca il vettore ha n elementi

• Alla prima iterazione il vettore si riduce a contenere circa n2 elementi

• Alla seconda iterazione il vettore si riduce a contenere circa n4 elementi

• . . .

• Alla i-esima iterazione il vettore si riduce a contenere circa n2i elementi

1ci si interessa principalmente del consumo di tempo, in quanto la memoria la si puo immaginare pressocche infinita(potendo aggiungere a piacimento memorie esterne come hard disk)

12

Page 21: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

L’algoritmo termina nel caso peggiore se la dimensione del vettore e di 1 solo elemento.

n

2i= 1⇒ n = 2i ⇒ i = log2 n

L’algoritmo ha complessita logaritmica.

Esempio 3 (Analisi asintotica dell’ InsersionSort) Il ciclo esterno viene eseguito n − 1 volte. Nelcaso peggiore il ciclo interno scandisce tutto il vettore ordinato (il ciclo e eseguito al massimo n−1 volte).Pertanto

T (n) = 1 + 2 + 3 + . . . =

n∑i=1

i =n · (n− 1)

2

E possibile quindi poter affermare che l’InsersionSort abbia complessita quadratica.

1.4.3 Notazione asintotica

Vi sono tre notazioni utilizzate, esse esprimono diverse proprieta.

Definizione 1 (Notazione asintotica O) Si dice che T (n) appartiene a O(g) si a partire da un certovalore n0 in poi g > T (n).

∃c > 0,∃n0 > 0/∀n ≥ n0 0 ≤ T (n) ≤ c · g(n)

Definizione 2 (Notazione asintotica Ω) Tale notazione implica che esiste un limite inferiore allacomplessita asintotica di caso peggiore, cio consente di dimostrare se un algoritmo e il migliore o meno.Se si riesce a dimostrare che un algoritmo ha limite inferiore significa che non puo esistere un altroalgoritmo con complessita migliore.

Se T (n) = am · nm + am−1 · nm−1 + . . .+ a0 ⇒ T (n) ∈ Ω(nm)

Definizione 3 (Notazione asintotica Ω) Si usa tale notazione implica che esiste una funzione cheschiaccia sia sopra che sotto, ovviamente con due coefficienti numerici, e ci da informazioni molto piuaccurate sull’andamento esatte di T (n).

T (n) ∈ Θ⇒ ∃c1, c2 > 0,∃n0 > 0/∀n ≥ n0 0 ≤ c1 · g(n) ≤ T (n) ≤ c2 · g(n)

1.5 Online Connectivity

Significa che ricevo in ingresso na coppia di interi (p, q), p e q rappresentano i nodi mentre (p, q) rappre-senta la connessione tra p e q (filo di connessione).La relazione e commutativa, cioe se p e connesso con q allora anche q e connesso con p, ed e anchetransitiva, cioe se p e connesso con q e q e connesso con t allora p e connesso con t.Si avra in output la lista delle connessioni incognite in precedenza.Si avra una struttura di dati a grafo, che conterra i nodi e gli archi (rappresentano nel caso specifico laconnessione).Le relazioni di connessione possono rappresentare:

• reti di calcolatori (si puo ottimizzare la rete riducendo il numero di connessioni ridondanti)

• reti elettriche, dove p e q sono i punti di contatto e (p, q) e il filo.

Immaginiamo di avere una rete con 10 nodi numerati da 0 a 9, con degli archi che rappresentano leconnessioni tra due nodi.Implicitamente il verso non si esprime, realizzando cosı un arco bidirezionale.Si cerca di evitare l’uso di tutte le connessioni non necessarie (cioe gia note in precedenza).L’ipotesi fondamentale e che non esiste una struttura dati esistente (e completa a priori), ma di volta involta che si aggiunge un collegamento si aggiorna la struttura (l’OnlineConnectivity realizza la strutturaal volo).Bisognera istituire due operazioni astrette:

find trova l’insieme a cui appartiene l’oggetto

union unisce due insiemi distinti

13

Page 22: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Se voglio inserire (p, q) devo verificare che find(p) 6= find(q) in tal condizione bisogna unire gli insiemiutilizzando union(find(p), find(q)).Per implementare tale struttura dati occorre una struttura dati di vettore (struttura presente in tutti ilinguaggi di programmazione).Occorre decidere se avere:

• find veloce e union lenta (Quick Find)

• find lenta e una union veloce (Quick Union)

1.5.1 Quick Find

Inizialmente si ha un vettore (id) di dimensione pari al numero di nodi.Inizialmente ∀i ∈ [0, n] ∩ N, id[i] = i (ogni nodo e solo connesso con se stesso).Se p e q sono connessi allora id[p] = id[q]

leggi la coppia (p, q)se la coppia non e connessa scandisci il vettore cambiando tutti gli elementi che valgono p in q.

Analisi asintotica Con tale strategia operativa si ha

• find: semplice riferimento a una cella del vettore O(1)

• union: scansione del vettore per cambiare gli ellementi che valgono p in q, O(n)

Complessivamente il numero di operazioni e legato a num_coppie * dim_vettore

Il caso peggiore si ha se si effettuano solo delle union.#include <stdio.h>

2 #define N 10000

main()

4

int i, t, p, q, id[N];

6 for(i=0; i<N; i++)

id[i] = i;

8 printf("Input pair p q: ");

while (scanf("%d %d", &p, &q) ==2)

10

if (id[p] == id[q])

12 printf("pair %d %d already connected\n", p,q);

else

14

for (t = id[p], i = 0; i < N; i++)

16 if (id[i] == t)

id[i] = id[q];

18 printf("pair %d %d not yet connected\n", p, q);

20 printf("Input pair p q: ");

22 system("pause");

Listing 1.8: Quick Find

1.5.2 Quick Union

Utilizza una strategia che favorisce la union.In questa stratecia si utilizza una catena (per accedere al rappresentante del gruppo occorre percorrerela catena finche non si arriva al capogruppo, cioe quello che riferisce a se stesso). In questa strategia:

• ogni oggetto punta all’oggetto a cui e connesso o a se stesso.Indicheremo con (id[i])* = id[id[id...id[i]..]]

• inizialmente tutti gli elementi puntano a se stessi, cioe id[i]=i

14

Page 23: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Si forma una catena di riferimenti (tale catena termina quando id[i]=i.leggi la coppia (p, q)calcola la testa della catena di p e di q, cioe (id[p])∗ e (id[q])∗. se (id[p])∗ e diverso da (id[q])∗ alloraaggiungi il nuovo riferimento id[(id[p])*] = (id[p])*

Analisi asintotica Con tale strategia operativa si ha

• find: percorre una catena che al massimo puo essere lunga quanto il vettore, O(n)

• union: assegnazione, O(1)

Complessivamente il numero di operazioni e legato a num_coppie * leh_massima

Il caso peggiore si ha se si effettuano solo delle find.#include <stdio.h>

2 #define N 10000

main()

4

int i, j, p, q, id[N];

6 for(i=0; i<N; i++)

id[i] = i;

8 printf("Input pair p q: ");

while (scanf("%d %d", &p, &q) ==2)

10

for (i = p; i!= id[i]; i = id[i]);

12 for (j = q; j!= id[j]; j = id[j]);

if (i == j)

14 printf("pair %d %d already connected\n", p,q);

else

16

id[i] = j;

18 printf("pair %d %d not yet connected\n", p, q);

20 printf("Input pair p q: ");

22 system("pause");

Listing 1.9: Quick Union

1.6 Matematica discreta: grafi e alberi

Si introdurra un discorso fatto in modo informale secondo una serie di formalismi e di definizioni.

1.6.1 Grafo

Informalmente un grafico e stato usato nella trattazione della Online Connectivity.Il grafo e utilizzato in una grandissima quantita di algoritmi ed e una struttura dati fondamentale perl’informatica.

Definizione 4 (Grafo) Si definisce grafo una coppia di insiemi:

• l’insieme dei vertici, V

• l’insieme degli archi o entita che introducono una relazione binaria tra due vertici, E

G = (V,E)

Definizione 5 (Grafo non orientato) Si definisce grafo non orientato un grafo nel quale se (u, v) ∈ Eallora esiste una relazione tra u e v e anche tra v e u

15

Page 24: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

A C

D

B

E F

Figura 1.1: Esempio di grafo non orientato

Esempio 4

G = (v, e)

v = A,B,C,D,E, F

e = (A,B), (B,D), (B,E), (C,F )

Definizione 6 (Grafo orientato) Si definisce grafo orientato un grafo nel quale se (u, v) ∈ E alloraesiste una relazione tra u e v allora non e detto che esiste una relazione tra v e u

A C

D

B

E F

Figura 1.2: Esempio di grafo orientato

Esempio 5

G = (v, e)

v = A,B,C,D,E, F

e = (A,B), (B,B), (B,D), (B,E), (D,A), (D,E), (E,D), (F,C)

Formalmente un grafo si evidenzia dalle loro entita.Se il grafo e non orientato

u, v ∈ E e u, v ∈ V

Se il grafo e orientato

(u, v) ∈ E e u, v ∈ V

Nell’uso abituale pero ci si limita a definire il tipo di grafo e definire le entita utilizzando sempre parentesitonde, bisogna fare attenzione al fatto che non si possono definire cappi all’interno di grafi non orientati.

1.6.2 Incidenza e adiacenza

Un arco (a, b) si dice che:

• insiste/incide sul vertice a

• insiste/incide sul vertice b

• insiste/incide sui vertici a e b

I vertici a e b sono adiacenti se sono messi in relazione da un’entita, cioe se

a adiacente b⇔ (a, b) ∈ E

16

Page 25: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

1.6.3 Grado di un vertice

Definizione 7 (Grado di un vertice) Si definisce grado di un vertice il numero di entita incidenti delnodo.

degree(A)

Nel caso in cui si ha un grafo orientato occorre distinguere il numero di entita entranti e uscenti dal nodo.Si definisce quindi

in degree(A) out degree(A) degree(A) = in degree(A) + out degree(A)

1.6.4 Cammini e raggiungibilita

Due nodi si dicono raggiungibili se esiste un percorso che collega a con b, magari passando anche attraversoaltri nodi.Un cammino esiste se esiste una serie di vertici adiacenti di cui il primo e quello di partenza, l’ultimo equello di arrivo e per ogni coppia intermedia esiste un arco che li lega (cioe sono adiacenti).

Cammino p : u→p u′ G = (V,E)

cioe

∃(v0, . . . , vk) : u = v0, u′ = vk, ∀i ∈ [1, k] ∩ N, (vi−1, vi) ∈ E

Si definisce k la lunghezza del cammino, numero di archi che compongono il cammino.Si dice che u′ e raggiungibile da u se ∃p : u→p u

′.Un cammino si dice semplice se ogni nodo, del percorso p, e visitato solo una volta.Vi sono dei cammini particolari, tali cammini sono i cicli e hanno la caratteristica di iniziare e finire nellostesso nodo (il ciclo piu corto si ha in presenza di un cappio).Un grafico che non presenta dei cicli si dice aciclico.

Esempio 6 d e raggiungibile da a?

G = (V,E)

V = a, b, c, d

E = (a, b), (b, b), (b, c), (b, d), (c, d), (d, c), (d, a)

p : a→p d : (a, b), (b, c), (c, d)

Si osserva che p e semplice ed e di lunghezza 3.

1.6.5 Connessione nei grafi non orientati

Definizione 8 (Grafo connesso) Si definisce grafo connesso un grafo nel quale esiste un percorso tradue nodi qualsiasi dello stesso.

∀vi, vj ∈ V, vi 6= vj ∃p : vi →p vj

Definizione 9 (Componente connessa) Si definisce componente connessa il sottografo connesso mas-simale.

E importante specificare che sia il sottografo massimale, cioe non esiste un sottografo connesso checontenga la componente connessa.I vertici appartenenti alla componente connessi sono tutti mutuamente raggiungibili.

Esempio 7

G = (V,E)

V = a, b, c, d

E = (a, b), (a, c), (a, d), (b, c), (b, d), (c, d)

a, c e un sottografo connesso. a, b, c e un sottografo connesso, ma a, b ⊂ a, b, c. a, b, c, d e unsottografo connesso, ma a, b, c ⊂ a, b, c, d. Poiche a, b, c, d = V allora a, b, c, d e la componenteconnessa.

In presenza di piu componenti connesse e come se si avesse una sorta di sottorete.

17

Page 26: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

1.6.6 Connessione nei grafi orientati

Definizione 10 (Grafo fortemente connesso) Si definisce grafo fortemente connesso un grafo nelquale esiste un percorso tra due nodi qualsiasi dello stesso, in entrambi i sensi di percorrenza.

∀vi, vj ∈ V, vi 6= vj ∃p : vi →p vj e ∃p′ : vj →p′ vi

Definizione 11 (Componente fortemente connessa) Si definisce componente fortemente connessail sottografo fortemente connesso massimale.

Esempio 8G = (V,E)

V = a, b, c, d, e, f, g, h

E = (a, b), (b, c), (b, e), (b, f), (c, d), (c, g), (d, c), (d, h), (e, a), (e, f), (f, g), (g, f), (g, h)

In G sono presenti quattro componenti connesse:

• C1 = a, b, e

• C2 = c, d

• C3 = f, g

• C4 = h

Se un vertice, nel caso specifico h, non e mutuamente connesso a nessun altro vertice allora essorappresenta un’unica componente fortemente connsessa.

1.6.7 Grafi densi o sparsi

Tale definizione si basa sul rapporto tra le cardinalita2 tra l’insieme dei vertici e l’insieme delle entita.

Definizione 12 (Grafo denso) Un grafo si dice denso se la cardinalita di E e circa uguale al quadratodella cardinalita di V .

|E| ' |V |2

Definizione 13 (Grafo sparso) Un grafo si dice sparso se la cardinalita di E e circa uguale al quadratodella cardinalita di V .

|E| |V |2

Definizione 14 (Grafo completo) Un grafo si dice completo ogni vertice vertice e collegato con tuttigli altri nodi.Un grafo completo e il grafo piu denso che si puo realizzare.Un grafo completo ha

|E| =(|V |2

)=

|V |!2! · (|V | − 2)!

=|V | · (|V | − 1)

2nel caso di grafo non orientato

|E| = 2 ·(|V |2

)= 2 · |V |!

2! · (|V | − 2)!= |V | · (|V | − 1) nel caso di grafo orientato

1.6.8 Grafo pesato

Il grafo e una struttura basilare per poter rappresentare moltissimi modelli.Un grafo potrebbe, ad esempio, essere il modello di una autostrada, ma conoscere il numero di tratteche bisogna percorrere per arrivare da una citta ad un’altre non e certamente sufficiente, sarebbe meglioconoscere i chilometri totali che bisogna percorrere. A questo proposito si puo aggiungere ad ogni arcoun’informazione (il peso) che indica nell’esempio proposto il numero di chilometri della tratta.

Definizione 15 (Grafo pesato) Si definisce grafo pesato un grafo nel quale esiste una funzione peso

w(u, v) = peso dell′arco

Generalmente il peso e un numero che e relazionato al tipo di informazioni che deve dare tale valore.

2la cardinalita indica il numero di elementi contenuti dall’insieme, la cardinalita di A si indica con |A|

18

Page 27: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

1.6.9 Alberi

Definizione 16 (Albero non radicato) Si definisce albero non radicato un grafo non orientato, con-nesso e aciclico.

Definizione 17 (Albero, foreste) Si definisce foresta un grafo non orientato e aciclico.

Proprieta

G = (V,E) |E| numero degli archi |V | numero dei nodiSe G e un albero non radicato allora

• tutte le coppie dei nodi sono connesse da un cammino semplice e unico

• rimuovendo un qualsiasi arco di G comporta la disconnessione del grafo

• si ha |E| = |V | − 1, poiche G e connesso ed e aciclico

• aggiungendo un nuovo arco tra gli archi presenti allora ottiene un ciclo

• esiste r ∈ E detto radice

• relazione di parentela

– y e un antenato di x se y ∈ p con p : x→p r

– y e un antenato proprio di x, se y e un antenato di x e x 6= y

– x e padre/figlio di y se x e y sono adiacenti

– r non ha padri

– x (foglia) non ha figli

Definizione 18 (Foglia) Si definisce foglia un nodo che non ha nodi adiacenti (nodi diversi dal nodopadre).

Definizione 19 (Grado di un albero) Si definisce grado di un albero il numero minimo dei figli am-messi da un qualsiasi nodo dell’albero.

Definizione 20 (Profondita di un nodo) Si definisce profondita di un nodo la lunghezza del camminoche congiunge il nodo alla radice dell’albero.

Definizione 21 (Altezza di un albero) Si definisce altezza di un albero la lunghezza massima delcammino che congiunge un nodo alla radice.

Altezza(A) = maxx∈E

profondita(E)

Casi particolari

Una classe particolare di alberi sono gli alberi binari, cioe gli alberi con grado due.

Definizione 22 (Albero binario) Si definisce albero binario, con definizione ricorsiva, un albero congrado due composto da:

• radice

• sottoalbero sinistro (albero binario)

• sottoalbero destro (albero binario)

Definizione 23 (Albero binario completo) Si definisce albero binario completo un albero binario incui tutti i percorsi radice-foglia hanno la stessa lunghezza, h e ogni nodo (eccetto le foglie ha grado due).Detta h l’altezza dell’albero allora

• l’albero ha 2h foglie

• l’albero ha

h∑i=0

2i = 2h+1 − 1 nodi

Definizione 24 (Albero bilanciato) Si definisce albero bilanciato un albero in cui tutti i camminiradice foglia hanno la stessa lunghezza.Se un albero e completo allora e bilanciato.

Definizione 25 (Albero quasi bilanciato) Si definisce albero quasi bilanciato un albero in cui tutti icammini radice foglia hanno circa la stessa lunghezza, puo differire di al massimo 1.

19

Page 28: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

1.7 La ricorsione

Definizione 26 (Procedura ricorsiva) Si definisce ricorsiva una procedura che e definita mediante lachiamata diretta o indiretta (cioe con la chiamata ad un altra procedura che richiama la prima procedura)alla procedura stessa.

Con la ricorsione si ha la partizione di un problema grande in un numero finito di problemi della stessanatura3, ma piu semplici (si riduce la dimensione del problema).La ricorsione consente di avere soluzioni piu compatte ed eleganti.Nel caso di procedure ricorsive e sempre necessario, per garantirsi la terminazione della stessa, unacondizione di terminazione cioe una soluzione ad un problema banale (che non puo essere ulteriormenteseparato).

Esempio 9 (Fattoriale)

n! =

n · (n− 1)! n ≥ 11 n = 0

1 long fattoriale(int n)

3 if(n==0)

return 1;

5 else

return n * fattoriale(n-1);

7 Listing 1.10: Fattoriale ricorsivo

Esempio 10 (Serie di Fibonacci ricorsva)

FIBn =

FIBn−1 + FIBn−2 n > 1n n ≤

1 int fibonacci(int n)

3 if(n>1)

return fibonacci(n-1)+fibonacci(n-2);

5 else

return n;

7 Listing 1.11: Fibonacci ricorsivo

Esempio 11 (Massimo comun divisore (algoritmo di Euclide) ricorsvo)

gcd(m,n) =

gcd(n,m mod n) n 6= 0m n = 0

1 int gcd(int m, int n)

3 if(n==0)

return m;

5 return gcd(n, m%n);

Listing 1.12: Massimo comun divisore ricorsivo

Esempio 12 (Valutazione di espressioni in forma prefissa ricorsva) Bisogna istituire una gram-matica delle forme prefisse (notazione polacca). Una espressione in forma prefissa e definita nel seguentemodo:<op> <exp> <exp>

Si semplifica la forma prefissa utilizzando come operatori i soli operatori di somma e moltiplicazione.<exp> = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

<op> = + | *

Ma un’espressione puo essere definita in modo ricorsivo <exp> = <exp> | <op> <exp> <exp>

Utilizzando la forma prefissa non sono piu necessarie le parentesi

3paradigma del Divide et Impera

20

Page 29: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Esempio: (5 + 12) ∗ 3 ≡ ∗ + 5 12 3

Si salva l’espressione in un vettore e si esegue la funzione eval(..., ...)int v[];

2 int i;

//v e i sono variabili globali

4 int eval()

6 int x=0;

while(a[i]==’ ’)

8 i++;

if(a[i]==’+’)

10

i++;

12 return eval() + eval();

14 else if(a[i]==’*’)

16 i++;

return eval() * eval();

18

while(a[i]>=’0’ && a[i]<=’9’)

20 x = 10*x + a[i++]-’0’;

return x;

22 Listing 1.13: Valutazione di espressioni notazione polacca

Esempio 13 (Ricerca binaria ricorsiva) Ha la stessa definizione della ricerca binaria, ma ne variala chiamata alla funzione, rendendola ricorsiva.int dicotomica(int vet[], int l, int r, int k)

2

if(r<l)

4 return -1;

else if(vet[(l+r)/2]==el)

6 return (l+r)/2;

else if(vet[(l+r)/2]>el)

8 return dicotomica(vet , l, (l+r)/2-1, k);

else

10 return dicotomica(vet , (l+r)/2+1, r, k);

Listing 1.14: Ricerca binaria ricorsiva

Esempio 14 (Massimo in un vettore) Se il vettore ha dimensione 1 allora ho il massimo, mentrese ha dimensione superiore a 1 divido il vettore in due sottovettori e cerco il massimo in entrambi isottovettori.

1 int max(int a[], int l, int r)

3 int u, v ;

int m = (l + r)/2 ;

5 if (l == r)

return a[l];

7 u = max(a, l, m);

v = max(a, m+1, r);

9 if (u > v)

return u;

21

Page 30: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

11 else

return v;

13 Listing 1.15: Massimo di un vettore ricorsivo

1.7.1 Paradigma Divide et Impera

Tale paradigma di programmazione prevede la divisione di un problema in altri sotto problemi indipen-denti piu piccoli(divide), la risoluzione dei sotto problemi (impera) e la ricombinazione delle risultatiparziali. Per questo tipo di algoritmi si adotta quasi sempre un’implementazione ricorsiva.Tutti i problemi su cui si adatta bene il paradigma divide et impera hanno lo schema seguente:

Risolvi(problema):

Se il problema e elementare:

return Soluzione = RisolviBanale(problema);

Altrimenti:

Sottoproblemi (1÷ a) = Dividi(Problema);

Per ciascun sottoproblema:

Sottosoluzione i = Risolvi(sottoproblema i);

return Soluzione = combina(sottosoluzione i÷ a);

Equazione delle ricorrenze

Per l’analisi asintotica di caso peggiore si utilizza spesso l’equazione delle ricorrenzeT (n) = D(n) + a · T

(nb

)+ C(n) n > c

T (n) = Θ(1) n ≤ c

Analisi asintotica Ricerca binaria

D(n) = Θ(1) ricerca valore medio

C(n) = Θ(1) non si ricombina

a = 1

b = 2

Analisi asintotica Ricerca Massimo

D(n) = Θ(1) ricerca valore medio

C(n) = Θ(1) non si ricombina

a = 2

b = 2

Moltiplicazione di due interi

D(n) = Θ(1) ricerca valore medio

C(n) = Θ(n) moltiplicazioni dei gruppi

Nella versione base a = 4, b = 2, mentre nella versione ottimizzata a = 3, b = 2.

Limiti del Dividi et Impera

Poiche per ipotesi tutti i sotto problemi sono indipendenti se si vuol forzare l’uso di tale paradigma allorasi ha uno spreco di risorse.Se per natura del problema i sottoproblemi sono indipendenti allora il divide et impera funziona moltobene.

22

Page 31: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Algoritmi ricorsivi di ordinamento

Si tratteranno sostanzialmente il Merge Sort e il Quick Sort.

Merge Sort L’algoritmo prevede di dividere, rispetto il centro, il vettore in due sottovettorisi esegue il mergesorto sul sottovettore destro e sinistro (terminazione se p==r || p>r cioe e ordinato)Ricombinazione, si fondono i due sottovettori ordinati in un vettore ordinato.void mergeSort(int A[], int l, int r)

2

int q;

4 if(l<r)

6 q = (l+r)/2;

mergeSort(A, l, q);

8 mergeSort(A, q+1, r);

Merge(A, l, q, r);

10

12 void Merge(int A[], int l, int q, int r)

14 int i, j, k, *B;

B = (int *) malloc(r*sizeof(int));

16 if(B==NULL)

return;

18 for(i=l, j=q+1, k=l; i<=q && j<=r; )

20 if(A[i]<A[j])

B[k++] = A[i++];

22 else

B[k++] = A[j++];

24

for( ; i<=q; )

26 B[k++] = A[i++];

for( ; j<=r; )

28 B[k++] = A[j++];

for(k=l; k<=r; k++)

30 A[k] = B[k];

Listing 1.16: Mergesort

Analisi asintotica di caso peggiore Si ipotizza per comodita n = 2k (lo si puo porre se si consideran ≥ 2k)Dividi: calcola la meta di un vettore D(n) = Θ(1)Risolvi: risolve i due sottoproblemi di dimensione n

2 (a = b = 2)Test di terminazione semplice Θ(1)Ricombinazione: basata sul merge C(n) = Θ(n) La dimensione del problema e n = 2k (per comodita,ma non e vincolante).All’i-esimo passo, poiche si divide a meta la dimensione del problema, si avra che la dimensione e n

2i .La condizione di terminazione e che il problmema ha dimensione 1,

n

2i= 1⇒ i = log2 n

Il costo della fusione e

O(∑

dim(s) + dim(d))

= O(n)

Quindi il merge sort ha complessita

T (n) = O(n · log n)

23

Page 32: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Quick Sort E un algoritmo di ordinamento in loco, non stabile che risulta sperimentalmente piu rapidodel mergesort.In realta il quick sort e un algoritmo di complessita quadratica nel caso peggiore, mentre nel caso medioe migliore ha complessita linearitmica. Si utilizza tale algoritmo di ordinamento in quanto nel caso medioe piu veloce del mergesort, non richiede l’allocazione di un vettore aggiuntivo e il caso peggiore (vettoreordinato in modo crescente o decrescente) e facilmente eliminabile.

Divisione Si partiziona il vettore A[l, ..., r] in due sottovettori:dato un pivot x

• SX A[l, ..., q] contiene tutti gli elementi minori o uguali a x

• DX A[q+1, ..., q] contiene tutti gli elementi maggiori o uguali a x 4

la scelta del metodo di scelta del pivot e arbitraria. Si scegliera comunque di avere una regola fissa perla scelte del pivot, cioe si prende il primo elemento del vettore.

Partition Pivot x = A[l]

Si individuano gli elementi A[i] e A[j] “fuori posto” effettuando un ciclo discendente per j fino a trovareun elemento minore del pivot e un ciclo ascendente per i fino a trovare un elemento maggiore uguale delpivot.Si scambiano gli elementi A[i] e A[j]

Ripeti tale procedura finche i<j

Si osserva che tale strategia ha complessita T (n) = Θ(n). Si esegue ricorsivamente la partition suA[l, ..., q] e su A[q+1, ..., r]void quickSort(int A[], int l, int r)

2

int q;

4 if(l<r)

6 q = partition(A, l, r);

quickSort(A, l, q);

8 quickSort(A, q+1, r);

10

int partition(int A[], int l, int r)

12

int x, i, j, temp;

14 x = A[l];

i = l-1;

16 j = r+1;

while(i<j)

18

while(A[--j]>=x)

20 ;

while(A[++i]<x)

22 ;

if(i<j)

24

temp = A[i];

26 A[i] = A[j];

A[j] = temp;

28

30 return j;

Listing 1.17: Quick Sort

4si ha anbiguita in quanto e a discrezione del programmatore il posizionamento del pivot nel sottovettore destro o sinistri

24

Page 33: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Ricombinazione non presente, in quanto si ordina direttamente sul vettore di partenza.

Analisi asintotica di caso peggiore L’efficienza dell’algoritmo e dipendente dal bilanciamento dellepartizioni, piu le partizioni sono bilanciate tanto piu e efficiente.Il caso peggiore si ha in caso di parizionamento completamente sbilanciato, cioe nel caso in cui si ha unsottovettore di 1 elemento e un sottovettore di n− 1 elementi.

Equazione delle ricorrenze nel caso peggiore

T (n) = a · T(nb

)+D(n) + C(n)

T (n) = T (n− 1) + n+ 1 n > 1T (n) = 1 n = 1

Tale equazione la si risolve attraverso l’unfolding, cioe lo sviluppo

T (n) = T (n−1)+(n) = T (n−2)+(n−1)+(n) = T (n−3)+(n−2)+(n−1)+(n) = . . . =

n∑i=1

i =n · (n+ 1)

2

T (n) = O(n2)

Si osserva che nel caso peggiore si ha una complessita quadratica, ma tale caso si puo escludere con grandesemplicita.

Caso migliore si ha nel perfetto bilanciamento della partizione, si ha una situazione esattamenteequivalente al mergesort quindi

T (n) = O(n · log n)

Caso medio ci si trova nel caso medio praticamente sempre purche non si sia nelle condizioni dicaso peggiore. In tale situazione l’algoritmo ha

T (n) = O(n · log n)

Esempio 15 (Quick sort nel caso medio) Sipponiamo che a ogni partition si ha un sottovettore di910 · n (sx) e un altro sottovettore di 1

10 · n (dx).Discendendo l’albero della ricorsione si osserva che il percorso estremo sinistro e “lungo” log 10

9(n), mentre

l’albero estremo destro e “lungo” log10(n) e per ogni passo si eseguono n operazioni per la partition.Poiche

log 109

(n) ≈ log10(n) n→ +∞

allora ha complessita T (n) = O(n · log n)

La scelta del pivot non cambia la complessita, ma puo influenzare le costanti che sono presenti all’in-terno del T (n) reale, tale scelte puo essere ottimizzata in base ai campi applicativi, attraverso euristicheparticolari o semplici.

1.7.2 Analisi di complessita di alcuni algoritmi

Ricerca binaria

Un problema di dimensione n viene diviso in un unico problema di dimensione n2 , non si ha ricombinazione

dei risultati.D(n) = Θ(1) C(n) = Θ(1) a = 1 b = 2

T (n) =

T(n2

)+ 1 + 1 n > 1

1 n = 1normalizzando

= T (n) =

T(n2

)+ 1 n > 1

1 n = 1

L’equazione alle ricorrenze la si puo risolvere attraverso l’unfording.

T(n

2

)= T

(n4

)+ 1

T(n

4

)= T

(n8

)+ 1

25

Page 34: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

T (n) = 1 + 1 + T(n

8

)Il caso terminale si ha quando n = 1, supponendo n una potenza di 2 (per comodita, ma questo noncambia il risultato)

T (n) =

log2 n∑i=0

i = log2 n+ 1

T (n) = O(log n)

Massimo in un vettore

Il problema e scomposto in due problemi di dimensione n2 , non si ha ricombinazione.

D(n) = Θ(1) C(n) = Θ(1) a = 2 b = 2

T (n) =

2 · T

(n2

)+ 1 n > 1

1 n = 1

T(n

2

)= 2 · T

(n4

)+ 1

T(n

4

)= 2 · T

(n8

)+ 1

T(n

2

)= 1 + 2 + 2 · T

(n8

)Il caso terminale si ha quando n = 1, quindi

T (n) =

log2 n∑i=0

2i =2log2 n+1 − 1

2− 1= 2log2 n+1 − 1 = 2 · n− 1

T (n) = O(n)

La ricerca del massimo effettuata in modo iterativo ha la stessa complessita dell’algoritmo analizzato, maeffettuando una sola scansione allora effettua al massimo n passi, quindi poiche ha delle costanti minorie migliore la ricerca del vettore in modo iterativo.

1.7.3 Torri di Hanoi, gioco matematico risolto con il dividi et impera

Si parte da una configurazione iniziale composta 3 pioli e da 3 dischi aventi diametro decrescente posi-zionati sul primo piolo.Si vuol arrivare alla configurazione finale in cui i dischi sono posti sul terzo piolo.Vi sono solo due regole:

1. Si puo accedere solo al disco in cima

2. Su un qualsiasi disco vi possono essere solo dischi con diametro minore.

Risoluzione

• Si spostano n− 1 dischi sul piolo ausiliare, piolo che non e quello di partenza ne quello di arrivo.

• Si sposta l’n-esimo disco dal piolo iniziale a quello finale.

• Si spostano n− 1 dischi dal piolo ausiliare a quello finale.

Si ha terminazione se n = 1, cioe ho uno spostamento elementare.

26

Page 35: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Analisi di complessita

La divisione e un’operazione elementare D(n) = Θ(1)La ricomposizione e un’operazione elementare C(n) = Θ(1)La risoluzione e:

• se n > 1 divide il problema in due sottoproblemi di dimensione n− 1

• se n = 1 si ha la condizione di terminazione

T (n) =

2 · T (n− 1) + 1 n > 11 n = 1

T (n− 1) = 1 + 2 · T (n− 2)

T (n− 2) = 1 + 2 · T (n− 3)

T (n) = 1 + 2 + 4 + 8 · T (n− 3) =

n+1∑i=0

2i = 2n − 1

T (n) = O (2n)

Si osserva che questo gioco matematico e certamente decidibile ma con n sufficientemente grande ilproblema e intrattabile.

1 void Hanoi(int n, int src , int dest)

3 int aux;

aux = 3 - (src + dest);

5 if (n == 1)

7 printf("src %d -> dest %d \n", src , dest);

return;

9

Hanoi(n-1, src , aux);

11 printf("src %d -> dest %d \n", src , dest);

Hanoi(n-1, aux , dest);

13 Listing 1.18: Torri di Hanoi

1.7.4 Backtracking

Attraverso il divide et impera si suppone di essere in grado di arrivare alla soluzione terminale.Nel caso in cui questo non sia vero occorre essere in grado di percorrere esaustivamente lo spazio dellesoluzioni, tale procedura e nota come backtracking.

1.8 ADT: Heap, code a priorita

Un ADT e una struttura dati astratta (Abstract Data Type).

Definizione 27 (Heap) Si definisce un heap un albero binario con le seguenti proprieta

strutturali un heap e un albero binario semi completo, tutti i livelli sono completi tranne eventualmentel’ultimo che e riempito da sinistra verso destra

funzionali per ogni vertice la chiave del padre e superiore alla chiave dell’elemento considerato.

∀i 6= r key(parent(i)) ≥ key(i)

di conseguenza la chiave nella radice e la chiave massima della struttura.

La definizione di un dato astratto include la realizzazione di una “libreria” che rende disponibili ad unclient delle operazioni per la corretta gestione di tale struttura, in tal modo non e necessario che il clientconosca l’implementazione del dato heap.Saranno implementate essenzialmente le seguenti funzioni:

27

Page 36: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

• Heapify(A, i), funzione che introduce i all’interno dell’heap

• Buildheap(A), funzione che trasforma una struttura dati, ad esempio un vettore, in un heap

• Heapsort(A), funzione di ordinamento ottimizzata per questa tipologia di dato, tale algoritmo saraun algoritmo ottimo [O(n · log(n))]

Una coda senza priorita e una struttura di tipo FIFO5; mentre una coda prioritaria, come la coda a unpronto soccorso, e facilmente strutturabile attraverso l’uso di un heap, per tale coda e necessario definirele seguenti funzioni

• insert(S, x)

• maximum(S), Θ(1)

• extract_maximum(S), O(log(n))

Un heap puo essere implementato attraverso una struttura dinamica che ha puntatori all’elemento padre,figlio destro e figlio sinistro; ma nell’uso pratico si preferisce adottare un vettore allocato dinamicamente;ma par mantenere le relazioni padre, figli e necessario o avere tre vettori conteneti tutti gli indici oppuresi puo avere un grande risparmio della memoria organizzando in un modo specifico la memoria.Il figlio sinistro di i sara identificato da LEFT(i)= 2 * i + 1,il figlio destro di i sara identificato da RIGHT(i)= 2 * i + 2

il padre di i sara identificato da PARENT(i)= (i-1)/2

Tale operazioni sono di complessita costante, in quanto sono una somma o delle moltiplicazioni/divisioniper due, semplici shift a sinistra o destra.Per questa implementazione e necessario “sovradimensionare” il vetttore, si osservera che allocando unlivello in eccesso si puo sprecare al massimo meta del vettore. Per tale implementazione sara anchenecessario fornire una funzione che restituisca il numero di elementi precedentemente inseriti nell’heapheapsize(A).

1.8.1 Procedura di insert

Si aggiunge una foglia all’albero (nell’ultimo livello piu a sinistra), nell’implementazione con vettore siavra indice pari a heapsize(A), si risale dalla foglia, fino al piu alla radice, confrontando la chiave dainserire con la chiave del padre per far in modo che venga rispettata la proprieta funzionale, se la chiaveda inserire e superiore alla chiave del padre si fa scendere il padre.La procedura di insert ha una complessita pari al massimo alla lunghezza del cammino foglia radice,quindi sara O(log(n))#define LEFT(i) ((i)*2+1)

2 #define RIGHT(i) ((i)*2+2)

#define PARENT(i) (((i) -1)/2)

4 void insert(int A[], int x, int *heapsize)

6 int i;

*heapsize ++;

8 i = *heapsize;

while(i>1 && A[PARENT(i)]<x)

10

A[i] = A[PARENT(i)];

12 i = PARENT(i);

14 A[i] = x;

Listing 1.19: Procedura di insert in un heap

1.8.2 Procedura di heapify

Trasforma i in un heap considerano che LEFT(i) e RIGHT(i) sia un heap. Si assegna ad A[i] il massimotra i nodi i, LEFT(i) e RIGHT(i), nel caso il massimo non e i si pone i al posto del nodo radice diLEFT(i) e RIGHT(i) e si esegue la procedura di heapify LEFT(i) o RIGHT(i).

5FIFO e equivalente a dire First In First Out, primo inserito primo estratto

28

Page 37: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

void swap(int A[], int first , int second)

2

int t;

4 t = A[first ];

A[first] = A[second ];

6 A[second] = t;

8 void heapify(int A[], int i, int heapsize)

10 int l, r, largest;

l = LEFT(i);

12 r = RIGHT(i);

if(l<heapsize && A[l]>A[i])

14 largest = l;

else

16 largest = i;

if(r<heapsize && A[r]>A[largest ])

18 largest = r;

if(largest !=i)

20

swap(A, i, largest);

22 heapify(A, largest , heapsize);

24 Listing 1.20: Procedura di heapify in un heap

1.8.3 Procedura di BuildHeap

La costruzione di un heap puo essere eseguita in due modi distinti:

1. inserimento sequenzialmente i dati in una struttura inizialmente vuota, procedura di insert

2. dato un vettore (generalmente non e un heap), lo si trasforma in un vettore (buildheap)In questo caso non si puo usare la heapify in quanto la struttura non ha Left e Right che sianoheap. Poiche per definizione le foglie sono un heap si parte dalle foglie e si esegue heapify fino allaradice.La procedura di heapify trasforma un albero binario in un heap:

• le foglie sono un heap

• applicazione di heapify a partire dal padre dell’ultima foglia

Questa procedura ha T (n) = O(n), non lo si puo dimostrare intuitivamente ma lo si puo fareanaliticamente.

1.8.4 HeapSort

L’ordinamento di un heap e eseguito con i seguenti passi:

1. Trasforma un vettore in un heap (buildheap)

2. Scambia il primo e l’ultimo elemento (swap(0, heapsize-1))

3. Ripristina le proprieta di un heap (heapify)

4. Riduce la dimensione dell’heap di 1 (heapsize--)

5. Ripeti le operazioni sopra finche non si esaurisce l’heap (heapsize==1)

29

Page 38: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

1.9 ADT: Tabella di simboli (Symbol Table)

Definizione 28 (Symbol table) Una tabella di simboli e una struttura di dati formata da record conchiave. Su questa struttura possono essere definite le seguenti operazioni di base:

inserimento di un nuovo record

ricerca di un record con chiave data

eliminazione di un record (non sempre necessaria)

Tale ADT e detto anche dizionario se all’utente e consentito solo fare ricerche.

1.9.1 Operazioni di un ADT SystemTable

inserimento di un nuovo elemento

ricerca di un record con chiave data

cancellazione di un elemento specificato

selezione del k-esimo elemento piu piccolo

ordinamento della tabella in base alla chiave

unione di due tabelle

L’algoritmo di ordinamento e dipendente dall’implementazione dell’ADT.

1.9.2 Strutture dati di un ADT SystemTable

Ogni elemento della struttura contiene l’ITEM e un elemento di tipo key che conterra la chiave (sul tipokey saranno definite le operazioni di less e eq).Un ADT SystemTable puo essere implementato attraverso le seguenti strutture dati:

• Strutture lineari:

tabelle ad accesso diretto non usate poiche si ha un grande spreco di memoria

array ordinato e non

lista ordinata e non

• Strutture ad albero:

alberi binari di ricerca (BST)

alberi bilanciati che mantengono la complessita di caso peggiore sempre logaritmica (non eammesso che l’albero come caso limite sia una lista)

tabelle di hash

1.9.3 Ricerca in un ADT SystemTable

Ricerca indicizzata da una chiave

E effettuabile solo su una tabella ad accesso diretto.Data la chiave k ∈ U = 0, 1, . . . ,M − 1 (considerando tutte le chiavi intere e distinte) puo essere usatacome indice di un array st[0, 1, . . . , N − 1] se si cerca key nell’ADT occorre semplicemente verificarest[key] se e NULL allora non e presente altrimenti si e trovata la chiave.Poiche l’array deve avere una dimensione finita si salva solo un sottoinsieme di tutte le possibili chiavi(logicamente contiguo). Questo tipo di ricerca ha il vantaggio che le operazioni di inserimento, cancella-zione e ricerca hanno costo costante T (n) = O(1); il grosso svantaggio di questo tipo di implementazioneconsiste nel fatto che inizializzazione, selezione e ordinamento dipendono dalla dimensione del sottoinsie-me (T (n) = O(M)), mentre si ha una occupazione di memoria proporzionale alla cardinalita dell’insiemeS(n) = O(|U |) = O(M) inoltre si ha un enorme spreco di memoria se |K| M (si nota subito che taleimplementazione non e applicabile nel caso in cui la dimensione dell’insieme e molto grande.

30

Page 39: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Ricerca sequenziale

Tale tipo di ricerca e applicabile solo su un array o una lista concatenata.

Array ordinato :

inserimento con spostamento, di una posizione, degli elementi piu grandi (rispetto alla chiave)

ricerca mediante la scansione sequenziale, si termina se la chiave e stata trovata o la chiave correntee superiore della chiave da cercare

Array non ordinato :

inserimento in fondo

ricerca mediante la scansione sequenziale completa, si termina se la chiave e stata trovata eterminata la struttura

Lista ordinata :

inserimento inserimento in ordine

ricerca mediante la scansione sequenziale, si termina se la chiave e stata trovata o la chiave correntee superiore della chiave da cercare

Lista non ordinata :

inserimento in testa

ricerca mediante la scansione sequenziale completa, si termina se la chiave e stata trovata eterminata la struttura

Ricerca binaria

Mantenere l’ordinamento dell’arrai in fase di inserimento ha costo quadratico.Tale ricerca e vantaggiosa in situazioni statiche:

• array ordinato solo all’inizio

• solo escluse operazioni di inserimento/cancellazione

L’efficienza e legata alla capacita di accesso diretto alle celle dell’array, pertanto e svantaggioso usare listeconcatenate.

1.10 Alberi binari di ricerca (BST)

Un albero binario qualsiasi puo essere attraversato secondo tre strategie distinte:

Pre-order x, left(x), right(x)

In-order left(x), x, right(x)

Post-order left(x), right(x), x

L’attraversamento ha complessita T (n) = Θ(n).E possibile calcolare i due parametri fondamenteli di un albero binario attraverso un calcolo ricorsivo:

numero dei nodi = 1 + numeroDiNodi(left) + numeroDiNodi(right)

altezza = 1 + max (altezza(left), altezza(right))

Definizione 29 (BST) Si definisce BST (Binary Search Tree) un albero binario con la seguente pror-pieta funzionale:

∀x ∈ BST :

∀y ∈ left(x), key(y) ≤ key(x)∀z ∈ right(x), key(z) ≥ key(x)

31

Page 40: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

1.10.1 Operazioni in un BST

Operazioni definite in questo tipo di struttura dati sono:

search Si effettua una ricerca ricorsiva di un nodo con chiave v.Si percorre l’albero dalla radice, si termina se v e la chiave della radice dell’albero (search hit) oppurese l’albero e vuoto (search miss); la ricorsione dal nodo x al sottoalbero sinistro se v < key(x) o alsottoalbero destro se v > key(x).

minumum si segue fino al sottoalbero sinistro finche esiste

maximum si segue fino al sottoalbero destro finche esiste

predecessor il predecessore del nodo x e il nodo con la piu grande chiave minore di x.Se ∃left(x) predessor(x) = max(left(x)); mentre se 6 ∃left(x) predecessor(x) =primo antenato dix il cui figlio destro e anche antenato di x

successor il successore del nodo x e il nodo con la piu piccola chiave maggiore di x.Se ∃right(x) successor(x) = min(right(x)); mentre se 6 ∃right(x) successor(x) =primo antenato dix il cui figlio sinistro e anche antenato di x

insert l’insersione di un nodo z con chiave v implica anche il mantenimento delle proprieta funzionali.Se il BST e vuoto si crea un nuovo BST con la chiave v posta nella radice, mentre se il BST non evuoto si opera ricorsivamente (inserendo nel sottoalbero sinistro/destro l’elemento) o iterativamente(che ricerca la posizione in cui introdurre il nodo e dopo lo introduce).

sort attraversamento del BST in-order (per avere ordinamento crescente)

select selezione della k-esima chiave piu piccola; per questa operazione sarebbe conveniente avere uninformazione aggiuntiva sull’albero che contiene il numero di nodi contenuti dal nodo (si potrebbeanche linearizzare il BST ma si evita attraverso la supposizione precedente).Se si ricerca la chiave minima si pone k = 0 (t e il numero di nodi radicati nel sottoalbero destro); set = k si ritorna la radice dell’albero, se t > k si ritorna la k-esima chiave piu piccola del sottoalberosinitro, infine se t < k si ricerca la (k − t− 1)-esima chiave piu piccolo del sottoalbero destro.

inserimento nella radice inserimento di una nuova chiave nella posizione corretta mediante la proce-dura di insert e attraverso una serie di rotazioni dell’albero si fa risalire l’elemento lungo l’albero.

delete si elimina un elemento dal BST; se l’elemento e una foglia la si elimina semplicemente, mentrese il nodo ha un solo sottoalbero si collega il padre con il figlio (si rimuove facilmente); mentre seil nodo ha entrambi i due sottoalberi occorre prestare molta attenzione, cioe eliminata la radicedi un albero e necessario ricollegare i due sottoalberi (restati disgiunti) ponendo sulla radice ilpredecessore o successore della radice (attraverso un’operazione di partition).

1.10.2 Complessita in un BST

In ogni BST le operazioni hanno sempre complessita T (n) = O(h), dove h e l’altezza dell’albero; nei casilimite si ha che h = log2(n) se l’albero e completamente bilanciato e h = n se l’albero e completamentebilanciato pertanto

O(log2(n)) ≤ T (n) ≤ O(n)

L’unica operazione che in un BST ha sempre complessita lineare e l’attraversamento.

1.10.3 Operazioni utili

Rotazioni

Tale tipo di operazioni modificano localmente la tipologia del BST; ovviamente tali operazioni possonoessere:

rotazione a destra Dato h il puntatore al nodo con chiave y, left(h) = x, right(h) = γ, left(x) = α eright(x) = β si operano in modo elementare le seguenti operazioni

left(h) = right(x) right(x) = h

rotazione a sinistra Dato h il puntatore al nodo con chiave x, left(h) = α, right(h) = y, left(y) = βe right(y) = γ si operano in modo elementare le seguenti operazioni

right(h) = left(x) left(x) = h

32

Page 41: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Partition

L’operazione consiste nel riorganizzare il BST ponendo nella radice la k-esima chiave piu piccola nellaradice. Si puo operare in modo ricorsivo, si pone inizialmente il nodo come radice di un albero: set (numero di nodi del sottoalbero sinistro) e maggiore di k si effettua la procedura di partition sulsottoalbero sinistro con chiave k; mentre se t < k si effettua la procedura di partition sul sottoalberodestra con chiave k = k − t − 1, al termine della ricorsione si ruota l’albero nella direzione opposta alladirezione presa per la partition.

1.10.4 Implementazione

;;;;;;

33

Page 42: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

34

Page 43: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Parte II

Programmazione

35

Page 44: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518
Page 45: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Capitolo 2

Problem Solving elementare

Prerequisiti del linguaggio C

Il corso di programmazione suppone note le seguenti nozioni, anche se comunque verranno approfonditedurante il corso.

• Tipi di dati primitivi (scalari)

• Operazioni di I/O

• Costrutti condizionali e iterativi

• Vettori e matrici

• Funzioni e passaggio dei parametri

• Stringhe

• File (testuali)

• Strutture

• Puntatori

• Gestione liea di comando

• Direttive al pre-compilatore

2.1 Problem Solving elementare su dati scalari

Si tratteranno problemi:

• numerici

• di cofifica/decodifica

• testuali

• di verifica e filtro di dati

• di ordinamento

2.1.1 Problem Solving e algoritmi

Con il nome di problem solving si indica la soluzione di problemi mediante algoritmi. Tale soluzione sirealizza mediante:

• codifica dei dati

• formalizzazione dell’algoritmo

• stesura dell’algoritmo nel linguaggio C

Per la scelta della struttura dati occorre ragionare sulla natura del problema e sul tipo di algoritmo scelto(ad esempio i tipi e la quantita di dati necessari).

37

Page 46: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

2.1.2 Strategie di soluzione

La maggioranza dei problemi risolti mediante programmi consiste nell’elaborazione di informazioni rice-vute in input, per produrre risultati di output.Per la stesura dell’algoritmo consiste nel:

• Individuazione dei dati (dei vari passaggi: input, output e dati intermedi)

• Formalizzazione delle operazioni necessarie per ottenere i risultati intermedi e quelli di output

• Cercare nella propria esperienza personale passaggi noti (un algoritmo e un progetto)

• Cercare metodi risolutivi (magari lavorando su carta) per risolvere il problema, nel caso di assenzadi altri strumenti

Per la scelta delle strutture dati oggorre ragionare su tutte le variabili necessarie durante lo svolgimentodi tutti i passaggi.

2.1.3 Classificazione dei problemi

Problemi numerici

Sono problemi di algebra, geometria, statistica, . . . e sono caratterizzati da:

• dati numerici

• valutazione di espressioni condizionali

• esecuzione di calcoli (magari iterativi)

Hanno il vantaggio di essere spesso gia formalizzati in modo non ambiguo, mentre hanno lo svantaggioche i numeri, all’interno del calcolatore, hanno lunghezza finita e spesso sono arrotondati.

Problemi numerici non iterativi Problemi nei quali occorre semplicemente effettuare una serie discelte.

Problemi numerici iterativi Come problemi su successioni/serie o poligoni di n lati. [Problema dellaserie armonica] Si richiede di introdurre n. Se n ≤ 0 non si esegue nulla, altrimenti si calcola la ridottan-esima

n∑i=1

1

i

#include <math.h>

2 #include <stdio.h>

in main (void)

4

int n,i;

6 float M;

printf("Introduci il numero di termini (0 = fine)\n");

8 scanf("%d", &n);

while(n > 0)

10

M = 0.0;

12 for (i = 1; i <= n; i++)

M = M + 1.0/(( float) i);

14 printf("Risultato: %f", M);

printf("Introduci il numero di termini (0 = fine)\n");

16 scanf("%d", &n);

18 return 0;

Listing 2.1: Calcolo della ridotta n-esima di una serie armonica

38

Page 47: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Problemi di codifica/decodifica Problemi nel quale bisogna occuparsi direttamente della codifica:

• numerica (conversione tra basi, operazioni in determinate basi)

• non numerica (decodifica/riconoscimento di codici interni)

Codifiche numeriche In C i dati sono salvati in complemento a 2 o con lo standard IEEE-754(internamente), mentre sono visualizzati in base 8/10/16 (esternamente).Le operazioni sono gestite automaticamente in base 2.

Si realizzi una funzione che visualizzi la codifica in binario di un numero inserito.Preso n > 0 visualizzare la codifica binaria.Algoritmo Prima iterazione per generare, in p, la potenza piu grande minore del numero, tale che 2p ≤ n.Seconda iterazione per generare il bit di ogni iterazione:

finche p 6= 0:

se n ≥ p: bit = 1, n = n− paltrimenti bit = 0

void binario (int n)

2

int p;

4 for(p = 1; 2*p <= n; p = p*2);

while(p > 0)

6

if(p <= n)

8

printf("1");

10 n = n-p;

12 else

printf("0");

14 p = p/2;

16 printf("\n");

Listing 2.2: Visualizzazione della codifica binaria di un intero

Si intende realizzare un programma che acquisisca iterativamente numeri interi dalla base iniziale b0 eli converta e stampi in base b1. Bisogna terminare l’esecuzione in presenza di inserimento di cifre nonvalide.

1 #include <stdio.h>

void converti_base (int n, int base);

3 int main (void)

5 int b0 , b1 , n = 0, cifra , fine = 0;

char c;

7 // menu per l’inserimento di b0 , b1

while (!fine)

9

scanf ("%c", &c);

11 if (c == ’ ’ || c == ’\n’)

13 converti_base (n, b1);

n = 0;

15

else

17

cifra = c - ’0’;

19 if (cifra >= 0 && cifra <= b0)

b = b0*n + cifra;

21 else

39

Page 48: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

fine = 1

23

25 return 0;

27 void converti_base (int n, int base)

29 int i, p;

for (p = 1; p*base <= n; p = p*base);

31 while (p > 0)

33 if (p <= n)

35 printf ("%d", n/p);

n = n%p;

37

else

39 printf ("0");

p = p/base;

41

printf ("\n");

43 Listing 2.3: Conversione da base b0 a base b1 (iterativo)

Codifica di caratteri Generalmente in C i caratteri sono salvati con standard ASCII.Tali operazoni di codifica sono utili per cifrare, bit di parita, comprimere senza o con perdita, . . .. Siintende codificare il contenuto di un file di testo, salvarlo su un altro file.La cifratura consiste in:

• ogni numero n da 0− 9 viene scritto in complemento a 9 (9− n)

• ogni codice alfabetico minuscolo viene scambiato in maiuscolo e viene fatto il complemento a ′z′.ch←′ A′ + (′z′ − ch)

• ogni codice alfabetico maiuscolo viene scambiato in minuscolo e viene fatto il complemento a ′Z ′.ch←′ a′ + (′Z ′ − ch)

Algoritmo

• Acquisire i nomi dei file

• Iterazione per lettura, codifica, scrittura1 #include <stdio.h>

#define MAXRIGA 30

3 int main(void)

5 char ch, nomefile[MAXRIGA ];

FILE *fin , *fout;

7 printf("nome file in ingresso:");

scanf("%s", nomefile);

9 fin = fopen(nomefile , "r");

if(fin==NULL)

11

printf("File %s non trovato .\n", nomefile);

13 return 1;

15 printf("nome file in uscita: ");

scanf("%s", nomefile);

17 fout = fopen(nomefile ,"w");

if(fout==NULL)

19

40

Page 49: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

printf("File %s non aperto .\n", nomefile);

21 return 1;

23 while (!feof (fin))

25 fscanf(fin , "%c", &ch);

if(ch >= ’0’ && ch <= ’9’)

27 ch = ’0’ + (’9’-ch);

else if(ch >= ’a’ && ch <= ’z’)

29 ch = ’Z’ + (’z’-ch);

else if(ch >= ’A’ && ch <= ’Z’)

31 ch = ’z’ + (’Z’-ch);

fprintf(fout , "%c", ch);

33

fclose(fin);

35 fflush(fout);

fclise(fout);

37 return 0;

Listing 2.4: Codifica di un file

Elaborazione testi carattere per carattere Sono problemi che fanno rferimento a problemi dielaborazione testi (chiaramente non si possono usare font, colori, dimenzioni, . . . ). Sarebbe utile elaborarecarattere per carattere quando non ci sono gia implementate nel linguaggio (ossia per casi particolari,facendo attenzione ad aggiungere sempre il NULL-terminator1.

Costruzione di figure/grafici Si tratta di realizzare uno preudo-grafico, un grafico molto rudi-mentale. Per ora, la visualizzazione di caratteri a video e sequenziale (esiste in alcune versioni del C lapossibilita di scrivere il carattere in un punto esatto, ma cio non fa parte del C standard o ANSI-C. Datauna parabola del tipo

y = a · x2 + b · x+ c

e si tracci il grafico su un sistema di riferimento cartesiano girato di 90 in senso orario.Si scrivi un programma che:

• Acquisisca da tastiera a, b e c

• Acquisisca un numero intero n (numero di valori) e i valori degli estremi x0, xn

• Acquisisca da tastiera i valori degli estremi ymin, ymax

• Suddivida l’intervallo [x0, xn], calcolare i valori di f(x)

Algoritmo:

• iterazione sui x0, xn

• calcola il valore della funzione e la disegni1 #include <stdio.h>

#include <math.h>

3 int main(void)

5 float a,b,c,x,passo ,x0,xn,y,ymin ,ymax;

int i, j, n;

7 printf("Coefficienti (a b c): ");

scanf("%f%f%f" ,&a,&b,&c);

9 printf("Numero di intervalli: ");

scanf("%d" ,&n);

11 printf("Intervallo per ascisse: ");

scanf("%f%f" ,&x0 ,&xn);

1carattere speciale che evidenzia al linguaggio C la fine di una stringa, in quanto le stringhe nel C sono semplici vettoridi caratteri

41

Page 50: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

13 printf("Intervallo per ordinate: ");

scanf("%f%f" ,&ymin ,&ymax);

15 passo = (xn-x0)/n;

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

17

x = x0 + i*passo;

19 y = a*x*x + b*x + c;

if (y<ymin || y>ymax) continue;

21 for (j=round(y-ymin); j>0; j--)

printf(" ");

23 printf("*\n");

25 Listing 2.5: Grafico di una parabola su una interfaccia a carattere

Elaborazione testi mediante stringhe Funziona se e necessario trovare delle sottostringhe. Edato un file di testo, visto come un insieme di righe, scomponibili in sottostringhe (di al piu 20 caratteri).Si realizzi una funzione C che, letto il file, ne copi il contenuto in un altro file (i nomi dei file sono ricevuticome parametri), dopo aver:

• ridotto le sequenze di piu spazi ad un solo spazioRidotto le sequenze di piu spazi ad un solo spazio

• inserito (in sostituzione di spazi) o eliminato caratteri a-capo (“\n”) in modo tale che ogni rigaabbia la massima lunghezza possibile minore oabbia la massima lunghezza possibile, minore o ugualea lmax (terzo parametro della funzione)

E possibile operare sia a livello di caratteri che di stringhe. Una possibile soluzione per la gestione distringhe parte dal fatto che l’input mediante scanf(‘‘%s’’, ...), permette di isolare in modo automaticostringhe isolate da spazi.

1 #include <stdio.h>

#include <string.h>

3 void formatta (char *nin , char *nout , int lmax)

5 const int STRLEN =21;

FILE *fin=fopen(nin ,"r");

7 FILE *fout=fopen(nout ,"w");

char parola[STRLEN ];

9 int l;

l=0;

11 while (fscanf(fin ,"%s",parola) >0)

13 if (l+1+ strlen(parola) > lmax)

15 fprintf(fout ,"\n%s",parola);

l=strlen(parola);

17

else

19

fprintf(fout ," %s",parola);

21 l+=1+ strlen(parola);

23

fclose(fin);

25 fclose(fout);

27 int main(void)

29 const int MAXLEN =31;

char nomein[MAXLEN], nomeout[MAXLEN ];

31 int l;

printf("nome file in ingresso: ");

42

Page 51: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

33 scanf("%s", nomein);

printf("nome file in uscita: ");

35 scanf("%s", nomeout);

printf("massima lunghezza riga: ");

37 scanf("%d", &l);

formatta (nomein , nomeout , l);

39 Listing 2.6: Riformattazione testi − mediante sottostringhe

Problemi di verifica e di filtri Sono problemi in cui bisogna decidere se un insieme di dati/infor-mazioni rispettano un determinato criterio di accettazione (si ha sempre una risposta SI/NO). Si possonoverificare dati singoli o piu dati insieme.Un problema di selezione e del tipo: prima verifico e poi decido.Verificare una sequenza di dati significa decidere se la sequenza rispetta un determinato criterio di acce-tazione, come introdurre parole in ordine alfabetico o se voglio tutte parole senza consonanti o problemisimili.Dato un file di testo contenente cognome e nome (su una riga di massimo 50 caratteri), si scriva unafunzione che ritorini 1 se e in ordine alfabetico altrimenti ritorini 0.int verifica_ordine(FILE *fp)

2

const int MAXC =50;

4 char riga0[MAXC+1], riga1[MAXC +1];

fgets(riga0 , MAXC , fp);

6 while(fgets(riga1 , MAXC , fp)!=NULL)

8 if(strcmp(riga1 , riga0) <0)

return 0;

10 strcpy(riga0 , riga1);

12 return 1;

Listing 2.7: Verifica ordine alfabetico file

43

Page 52: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

44

Page 53: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Capitolo 3

Puntatori e allocazione dinamica

I puntatori sono dei tipi di dati che contengono l’indirizzo di una locazione di memoria. Sui puntatorisono variabili su cui comunque e possibile effettuare delle operazioni (algebra dei puntatori) e consentonol’allocazione dinamica della memoria (nel C i vettori hanno una dimensione fissa e decisa in fase dicompilazione).

3.1 Tipo di dato puntatore

e un identificatore di una variabile in C e fanno riferimento ad altri dati, inoltre essendo un dato e pos-sibile manipolarlo.Una variabile generalmente e identificata attraverso il suo nome (il nome del contenitore), ma in realta ilC identifica una variabile attraverso il suo indirizzo (il C ha una tabella che converte i nomi agli indirizzie tale tabella e inaccessibile al programmatore e all’utente).All’esecuzione di ogni programma si ha la fase di LOAD che porta in RAM tutti i dati, le variabili e leistruzioni prendendoli dalla memoria di massa.

3.1.1 Puntatore come riferimento

Il puntatore e generalmente rappresentato attraverso una freccia a cui si associa il tipo indirizzato. Ilpuntatore e uno strumento alternativo all’identificatoer per accedere a un dato, inoltre e manipolabile(come gia ripetuto precedentemente).

3.2 Definizione e operazione sui puntatori

Nel linguaggio C vi sono due operatori fondamentali per operare con i puntatori:

• *p, restituisce il dato presente nell’indirizzo contenuto dal puntatore p

• &a, restituisce l’indirizzo in memoria (un puntatore) della variabile a

3.2.1 Definizione di un puntatore

Per definire un puntatore richiede il riferimento a un tipo base presente nel linguaggio, e comunquepossibile realizzare puntatori a struct benche tali struct devono essere gia definite in precedenza. Ladefinizione e del tipo int* px definisce px una variabile puntatore di tipo intero, tale definizione puoseguire due scuole di pensiero differenti:

• int *px, px e un puntatore a int

• int* px, px e una variabile di tipo puntatore a intero

al momento della definizione *px non contiene ancora un indirizzo quindi sarebbe bene inizializzarlo aNULL.

3.2.2 Variabili e operazioni sui puntatori

L’operatore & ritorna un puntatore al dato a cui viene applicato.L’operatore * ritorna il dato puntato dal dato a cui si applica.

45

Page 54: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Assegnazione a variabili puntatori

p = &x oppure s=p (se p e un puntatore)

Assegnazione a dato puntato

*p = 3*(x+2); assegna ala variabile puntata da p il valore 3*(x+2).

Puntatore generico

Esiste in C anche la possibilita di definire un puntatore di tipo generico, void *, tale puntatore puo,rispettando tutte le restrizioni del C (poiche e fortemente tipizzato) essere convertito da puntatore di inta puntatore di float, . . . .Un puntatore di questo tipo puo esere comodo per puntatori di cui non ci interessa conoscere il tipo oper puntatori addetti al solo trasporto di un indirizzo....

2 int *px;

char *s0;

4 void *generic;

...

6 generic = px;

...

8 s0 = generic;

... Listing 3.1: Esempio di uso di void*

3.2.3 Confronto tra puntatori

Il confronto tra puntatori si puo fare nei seguenti modi:

• confrontando i due indirizzi, p1==p2

• confrontando i contenuti degli indirizzi puntati dal puntatore *p1==*p2

Ovviamente se il primo confronto e verificato allora lo e anche il secondo, la cosa non vale al contrario.

3.2.4 Aritmetica dei puntatori

Essendo in C i puntatori delle variabili, allora esse possono essere definite delle operazioni. Sono definitele operazioni di somma e differenza, poiche operano su indirizzi aggiungere o sottrarre 1 significa andareall’indirizzo precedente o all’indirizzo successivo....

2 int x[100] , *p=&x[50], *q, *r;

...

4 q = p+1; /** equivalente a q=&x[51]*/

r = p-1; /** equivalente a q=&x[49]*/

6 q++: /**ora q punta a x[52]*/

... Listing 3.2: Aritmetica dei puntatori

L’aritmetica dei puntatori e consigliabile non effettuarla su void* in quando non essendo il tipo void* untipo puntatore che non contiene la dimensione di ogni singolo elemento puntato potrebbe causare erroriinattesi.

3.3 Implementazioni di strlen

E una funzione, presente nella libreria <string.h>, che ritorna la lunghezza della stringa passata comeparametro (si faccia attenzione a che la stringa sia terminata dal NULL-terminator).

46

Page 55: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

int strlen(char s[])

2 /** senza uso di puntatori , si usa solo un contatore */

4 int l=0;

while(s[l]!=’\0’)

6 l++;

return +;

8 Listing 3.3: strlen - I

int strlen(char s[])

2 /**con puntatore e contatore */

4 int l=0;

char *p = &s[0]; // equivalente p=s;

6 while (*p!=’\0’)

8 p++;

l++;

10

return l;

12 Listing 3.4: strlen - II

int strlen(char s[])

2 /**con due puntatori e senza contatore */

4 char *p0=s;

char *p1=s;

6 while (*p1!=’\0’)

p1++;

8 return (p1 -p0);

Listing 3.5: strlen - III

1 int strlen(char s[])

/**un puntatore e senza contatore */

3

char *p=s;

5 while (*p!=’\0’)

p++;

7 return (p-s);

Listing 3.6: strlen - IV

3.4 Pasaggio parametri by reference

Il linguaggio C non consente il passaggio di parametri attuali per riferimento, consente solo di passarli byvalue, cioe ne effettua una copia e lascia libera la funzione chiamata di operare sulla sua copia. Ma comee possibile far lavorare la funzione sui dati originali? Come fa a passare vettori? Un semplice modo perottenere di fatto un passaggio by reference e quello di passare alla funzione chiamata il puntatore allavariabile che si voleva passare, tale puntatore ovviamente sara passato by value ma essendo che passa lacopia di un indirizzo quando la funzione fa accesso all’indirizzo modifichera ralmente i dati e non solouna sua copia. Inoltre in C il nome di un vettore rappresenta in realta l’indirizzo del primo elementodell’array, cioe &dati[0] ≡ dati

47

Page 56: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

3.4.1 Vettore come parametro di una funzione

In un paramentro formale un vettore puo corrispondere a un puntatore come parametro attuale.void ordinaInt(int v[], int n);

2 int main(void)

4 int dati [100];

...

6 for(i=0; i <100; i+=10;

ordinaInt (&dati[i], 10);

8 ...

Listing 3.7: Vettore come parametro di una funzione - I

Ma la relazione vale anche al contrario, se come parametro formale c’e un puntatore posso passare comeparametro attuale un vettore.

1 void leggiInt(int *p, int n);

int main(void)

3

int dati [100];

5 ...

leggiInt(dati , 100);

7 ...

Listing 3.8: Vettore come parametro di una funzione - II

Si vuol realizzare una funzione che confronta due stringhe e che ritorni:

• 0 se le due stringhe sono uguali

• ¿0 se la prima stringa segue la seconda

• ¡0 se la prima stringa precede la seconda

E una funzione che ha lo stesso funzionamento della strcmp della libreria standard.int strcmp(char *s0 , char *s1)

2 /** senza l’uso di alcuna variabile locale */

4 while ((*s0==*s1) && (*s0!=’\0’))

6 s0++;

s1++;

8

return (*s0 -*s1);

10 Listing 3.9: strcmp - I

int strcmp(char *s0 , char *s1)

2 /** senza l’uso di alcuna variabile locale */

4 while ((*s0==*s1) && (*s0!=’\0’))

6 s0++;

s1++;

8

return (*s0 -*s1);

10 Listing 3.10: strcmp - II

48

Page 57: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

int strcmp(char *s0 , char *s1 , int n)

2 /** strcmp solo su n caratteri */

4 int i=0;

while(s0[i]==s1[i] && s0[i]!=’\0’)

6

if(i<n)

8 i++;

else

10 return 0;

12 return (s0[i]-s1[i]);

Listing 3.11: strncmp

Si realizzi una funzione che ricerci una stringa all’interno di un’altra stringa (reimplementazione distrstr della libreria). La funzione ritorna NULL se la sottostringa non e stata trovata, il puntatoreall’inizio della sottostringa se e stata trovata.char *strstr(char s[], char cerca [])

2

int i, ns=strlen(s), nc=strlen(cerca);

4 for(i=0; i<ns -nc; i++)

if(strncmp (&s[i], cerca , nc)==0)

6 return &s[i]; // return s+i;

return NULL;

8 Listing 3.12: strstr

3.5 Puntatori a strutture

Per accedere a una struttura dati (struct) si fa esattamente come con le variabili semplici, attraverso ilnome o anche attraverso il suo puntatore.Si noti che un puntatore in questo caso puo puntare all’intera struttura, a un singolo campo della strutturae puo anche essere il campo di una struttura.struct studente

2

char cognome[MAX], nome[MAX];

4 int matricola;

float media;

6 ;

...

8 struct sudente *p;

float *p_media;

10 ...

p = ...; /** in qualche modo metto in p l’indirizzo di una struct

studente */

12 p_media = &((*p).media); /** prendo l’indirizzo di media all’interno

della struttra puntata da p*/ Come si puo vedere puo diventare estremamente lungo e poco intuitivo riuscire a passare indirizzi distrutture.struct esame

2

int scritto , orale;

4 ;

struct studente

49

Page 58: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

6

char cognome[MAX], nome[MAX];

8 int matricola;

struct esame *es;

10 ;

...

12 p = ...; /** in qualche modo metto in p l’indirizzo di una struct

studente */ Se io ora volesi porre il voto dell’esame scritto dello studente puntato da p dovrei fare: (*(*p).es).

scritto=voto, ma come credo sia evidente richiede una grande attenzione alla precedenza degli operatori(occorre aggiungere in posti esatti asterischi e parentesi). Il C ha introdotto una nuova simbologia perindicare i campi di una struttura puntata(*(*p).es).scritto = p->es ->scritto; e chiaro che le due scritture sono equivalenti, ma con la nuova simbologia risulta di molta piu semplicecomprensione.

3.5.1 Strutture ricorsive

Nell’ambito dei linguaggi di programmazione si dice ricorsiva un’entita che faccia riferimento in mododiretto e/o indiretto a ste stessa (a un’entita dello stesso tipo).Per definire una struttura ricorsiva occorre che all’interno vi sia almento un puntatore che ha come tipobase la struttura che si sta definendo. Tali strutture sono spesso usate per effettuare linked list.

1 struct studente

3 int cognome[MAX], nome[MAX];

int matricola;

5 struct studente *link;

; Listing 3.13: Esempio Struttura ricorsiva

All’interno della definizione della struttura non e ancora stato mai completamente definito il tipo struct

studente ma la dichiarazione precedente e lecita in quanto ogni puntatore ha una dimensione fissa, equindi riserva lo spazio necessario per il puntatore senza problemi. [di Giuseppe Flavio] SLIDESi hanno n oggetti disposti in cerchio (numerati da 1 a n). Ogni oggetto conosce solo la posizionedell’oggetto successivo. Si parte dall’elemento 1 e si elimina un ogetto ogni M , ovviamente dopo avereliminato l’oggetto e necessario che l’oggetto precedente punti all’oggetto successivo.Come struttura dati sara necessario realizzare una lista o catena circolare, per realizzarla si crea unastruttura che contiene il numero e il puntatore alla struttura successiva.Occorre effettuare una iterazione per selezionare/eliminare l’i-esimo oggetto.#include <stdio.h>

2 #define MAX 100

struct oggetto

4

int num;

6 struct oggetto *succ;

;

8 int main(void)

10 int i, N, M;

struct oggetto *p, oggetti[MAX];

12 printf("N = "\n");

scanf("%d", &N);

14 printf("N = "\n");

scanf("%d", &M);

16 for(

Listing 3.14: Esempio di Giuseppe Flavio

50

Page 59: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

3.6 Allocazione dinamica della memoria

L’obbiettivo fondamentele nell’allocazione dinamica e avere un contatto diretto con l’allocazione di por-zioni di memoria, capire che la memoria allocata e sotto lo stretto controllo del programmatore (che dovracapire dove, quanto e come allocare la memoria).Allocare una variabile significa associare alla variabile una porzione di memoria (in cui collocare i dati).L’allocazione avviene in modo:

• permanente, per le variabili globali (definite fuori da ogni funzione)

• temporaneo, per le variabili locali e i parametri formali

• dinamico, per le variabili allocate dinamicamente dal programmatore

Il C fornice metodi per l’allocazione e deallocazione esplicita basata su puntatori.Allocare la memoria significa richiedere al Sistema operativo un determinato quantitativo di memoria eottenerla (se c’e abbastanza memoria).Deallocare la memoria significa restituire (rilascare) la memoria precedentemente ottenuta, al SistemaOperativa, in modo che il SO la possi riusare. In fase di deallocazione e solo necessario passare al sistemaoperativo il punto in cui inizia la memoria allocata dinamicamente.

3.6.1 Malloc

La funzione malloc nel C ritorna un puntatore di tipo void * che punta a una memoria contigua di nbyte, nel caso non sia disponibile tutta la memoria richiesta ritorna un puntatore NULL. La funzione hail seguente prototipovoid *malloc(size_t size);

Listing 3.15: Prototipo malloc

size indica il numero di byte da richiedere al sistema operativo. E conveniente chiedere in fase di richiestadi memoria, fare un cast esplicito al tipo a cui viene effettuata l’allocazione.Per evitare di dover fare conti manualmente, spesso errati, sulla quantita di memoria da richiedere siesegue una stategia molto semplicativa: si indica con n il numero di celle di memoria da allocare e consizeof(type) richiama la funzione sizeof che vuole come parametro il tipo della variabile e ne ritornala memoria occupata da ciascuna allocazione.

Ad esempio: (int *)malloc(n*sizeof(int));

Per rilasciare la memoria si esegue semplicemente il richiamo di una funzione, free, che dealloca lamemoria associata al puntatore che e passato alla funzione.

3.7 Strutture Astratte

3.7.1 Liste

Le liste sono stutture astrette composte da elementi singoli puntati tra di loro attraverso degli specificipuntatori, si tratteranno quindi nel caso di allocazione dinamica della struttura di strutture ricorsive.Si hanno liste linkate semplici se ogni elemento conosce il puntatore all’elemento successivo, si hanno listedoppio linkate se ogni elemento ha il puntatore all’elemento precedente e successivo.L’utilizzo di questa struttura dati consente l’allocazione di ogni elemento senza “riallocare” un nuovovettore. Con questa strategia si perde l’accesso diretto agli elementi, si puo comunque percorrere la li-sta pertanto tutte le operazioni (eccetto alcune specifiche operazioni) avranno complessita lineare (O(n)).

Inserimento in mezzo di un nuovo elemento

Supponendo che x sia il puntatore all’elemento dopo il quale vuol essere inserito il nuovo elemento t sieseguono due semplici operazioni per aggiornare i puntatori. E necessario prestare attenzione che nelcaso di scansione per determinare x fermarsi all’elemento precedente della nuova posizione, questo se lalista e linkata semplice.struct nodoITEM item; struct nodo *next; t->next = x->next; x->next = t; Nel caso di li-ste doppio linkatestruct nodoITEM item; struct nodo *prev, *next; t->next = x->next; x->next->prev = t;

x->next = t; t->prev = x;

51

Page 60: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Cancellazione di un nodo (elemento)

Dato che si trattano specialmente liste linkate semplici, e necessario fermarsi all’elemento precedente delquale bisogna cancellare. Denominando con x l’elemento precedente.L’eliminazione e strutturata sostanzialmente da

temp = x->next; x-next = x->next->next; elaborazione(temp);

Dove elaborazione(temp) e spesso una semplice richiamata a free(temp), ma cio non e vincolante.Nel caso di lista doppio linkata la cancellazione e nel seguente modo (t elemento da cancellare)

t->prev->next = t->next; t->next->prev = t->prev; elaborazione(t);

In realta una lista puo anche essere implementata attraverso un vettore statico, in questo caso l’inseri-mento, la cancellazione e l’estrazione di elementi della lista hanno complessita di O(n) in quanto occorreshiftare tutti gli elementi per “ricompattare” il vettore, mentre l’accesso a un singolo elemento puo esseredeterminato dall’indice (complessita costante O(1)).

52

Page 61: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Parte III

Laboratorio

53

Page 62: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518
Page 63: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Capitolo 4

Esercitazione 1

4.1 Esercizio n. 1: manipolazione di una matrice - I

Un file di testo contiene una matrice quadrata di numeri reali con il seguente formato:

• la prima riga del file specifica la dimensione reale della matrice (si assuma che sia comunque al piupari a 10).

• ciascuna delle righe successive contiene i valori corrispondenti a una riga della matrice, separati dauno o piu spazi.

Si realizzi un programma C che:

• legga tale matrice dal file di ingresso, il cui nome e specificato dall’utente.

• generi una nuova matrice, delle stesse dimensioni di quella appena acquisita, in cui il valore diciascun elemento e:

– 0 se il corrispondente elemento della matrice di ingresso e negativo o nullo.

– l’ordine di grandezza del corrispondente elemento della matrice di ingresso (definito come lapiu piccola potenza di 10 che e maggiore del valore in questione) in caso contrario.

• visualizzi sul video un opportuno messaggio a seconda che la matrice cosı generata risulti simmetricaoppure no.

Per quanto possibile, si cerchi di risolvere il problema proposto implementando delle opportune funzioni.#include <stdio.h>

2 #define MAXDIM 10

#define MAXSTR 255

4 int isSimmetrica(float matrix [][ MAXDIM], int dim);

int leggi_file(char *nome_file , float matrix [][ MAXDIM ]);

6 int potenza_sup(int base , int numero);

void manipolazione(float matrix [][ MAXDIM], int dim);

8 int main()

10 char path[MAXSTR +1]=0;

float matrix[MAXDIM ][ MAXDIM ];

12 int dim;

printf("Introduci il nome del file contenente la matrice :\n\t");

14 gets(path);

if((dim=leggi_file(path , matrix)) >=0)

16

manipolazione(matrix , dim);

18 printf("La matrige generata dal file in ingresso risulta %s.\n",

(isSimmetrica(matrix , dim) ? "simmetrica" : "non simmetrica"

));

20 else

22 printf("Il file %s non e’ stato aperto .\n", path);

55

Page 64: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

system("pause");

24 return 1;

26 system("pause");

return 0;

28

void manipolazione(float matrix [][ MAXDIM], int dim)

30

int i, j;

32 for(i=0; i<dim; i++)

34 for(j=0; j<dim; j++)

36 if(matrix[i][j]<=0)

matrix[i][j]=0;

38 else

matrix[i][j] = potenza_sup (10, matrix[i][j]);

40

42

int potenza_sup(int base , int numero)

44

int i=1;

46 while(i<numero)

i*=base;

48 return i;

50 int leggi_file(char *nome_file , float matrix [][ MAXDIM ])

52 FILE *f;

int i, j, dim;

54 if((f = fopen(nome_file , "r"))==NULL)

return 0;

56 fscanf(f, "%d", &dim);

for(i=0; i<dim; i++)

58

for(j=0; j<dim; j++)

60

if(fscanf(f, "%f", &matrix[i][j])==EOF)

62

fclose(f);

64 return -1;

66

68 fclose(f);

return dim;

70

int isSimmetrica(float matrix [][ MAXDIM], int dim)

72

int i, j;

74 for(i=1; i<dim; i++)

76 for(j=0; j<i; j++)

78 if(matrix[i][j]!= matrix[j][i])

return 0;

80

82 return 1;

56

Page 65: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Listing 4.1: Manipolazione di una matrice - I

4.2 Esercizio n. 2 - Manipolazione di una matrice - II

Un file di testo contiene una matrice di interi con il seguente formato:

• la prima riga del file specifica le dimensioni reali della matrice (numero di righe nr e numero dicolonne nc). Si assuma che entrambi i valori siano comunque al piu pari a 20.

• ciascuna delle nr righe successive contiene gli nc valori corrispondenti a una riga della matrice,separati da uno o piu spazi.

Si scriva un programma C che:

• legga tale matrice dal file di ingresso.

• generi una nuova matrice, in cui il valore di ciascun elemento e dato dalla media aritmetica delle(al piu) 8 caselle adiacenti all’elemento corrispondente della matrice di ingresso.

• scriva la matrice cosı ottenuta su un file di uscita, con lo stesso formato del file di ingresso.

Il nome dei due file sia passato al programma sulla riga di comando.1 #include <stdio.h>

#include <stdlib.h>

3 #define MAXR 20

#define MAXC 20

5 #define MAXSTR 255

void manipolazione(FILE *dev);

7 int leggi_file(char *nome_file);

int add(int rs , int cs , int *sum);

9 float matrix[MAXR][MAXC];

int r, c;

11 int main(int argc , char **argv)

13 FILE *F;

if(argc ==3)

15

if(leggi_file(argv [1]))

17

if((F=fopen(argv[2], "w"))==NULL)

19

printf("Il file %s non e’ stato aperto .\n", argv [2]);

21 system("pause");

return 1;

23

manipolazione(F);

25 fclose(F);

27 else

29 printf("Il file %s non e’ stato aperto .\n", argv [1]);

system("pause");

31 return 2;

33

else

35

printf("Comandi inseriti non validi .\n%s file_input file_output\

n", argv [0]);

37 system("pause");

return 3;

57

Page 66: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

39

system("pause");

41 return 0;

43 int leggi_file(char *nome_file)

45 FILE *f;

int i, j;

47 if((f = fopen(nome_file , "r"))==NULL)

return 0;

49 fscanf(f, "%d %d", &r, &c);

for(i=0; i<r; i++)

51

for(j=0; j<c; j++)

53

if(fscanf(f, "%f", &matrix[i][j])==EOF)

55

fclose(f);

57 return 0;

59

61 fclose(f);

return 1;

63

int add(int rs , int cs , int *sum)

65

if(rs >=0 && cs >=0 && rs <r && cs <c)

67

*sum = *sum + matrix[rs][cs];

69 return 1;

71 return 0;

73 void manipolazione(FILE *dev)

75 int i, j;

int n_el , sum;

77 fprintf(dev , "%d %d\n", r, c);

for(i=0; i<r; i++)

79

for(j=0; j<c; j++)

81

sum =0;

83 n_el =0;

n_el += add(i-1, j-1, &sum);

85 n_el += add(i-1, j, &sum);

n_el += add(i-1, j+1, &sum);

87 n_el += add(i, j-1, &sum);

n_el += add(i, j+1, &sum);

89 n_el += add(i+1, j-1, &sum);

n_el += add(i+1, j, &sum);

91 n_el += add(i+1, j+1, &sum);

fprintf(dev , "%.1f ", (( float)sum)/n_el);

93

fprintf(dev , "\n");

95

Listing 4.2: Manipolazione di una matrice - II

Tale soluzione effettua per ogni casella una serie di otto condizioni, per controllare bene gli elementipresenti sul bordo.

58

Page 67: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

#include <stdio.h>

2 #include <stdlib.h>

#define MAXR 20

4 #define MAXC 20

#define MAXSTR 255

6 void manipolazione(FILE *dev);

int leggi_file(char *nome_file);

8 float sum(int r, int c);

float matrix[MAXR +2][ MAXC +2];

10 int r, c;

int main(int argc , char **argv)

12

FILE *F;

14 if(argc ==3)

16 if(leggi_file(argv [1]))

18 if((F=fopen(argv[2], "w"))==NULL)

20 printf("Il file %s non e’ stato aperto .\n", argv [2]);

system("pause");

22 return 1;

24 manipolazione(F);

fclose(F);

26

else

28

printf("Il file %s non e’ stato aperto .\n", argv [1]);

30 system("pause");

return 2;

32

34 else

36 printf("Comandi inseriti non validi .\n%s file_input file_output\

n", argv [0]);

system("pause");

38 return 3;

40 system("pause");

return 0;

42

int leggi_file(char *nome_file)

44

FILE *f;

46 int i, j;

if((f = fopen(nome_file , "r"))==NULL)

48 return 0;

fscanf(f, "%d %d", &r, &c);

50 for(i=1; i<=r; i++)

52 for(j=1; j<=c; j++)

54 if(fscanf(f, "%f", &matrix[i][j])==EOF)

56 fclose(f);

return 0;

58

60

59

Page 68: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

fclose(f);

62 return 1;

64 float sum(int rc , int cc)

66 float s=0;

s+= matrix[rc -1][cc -1];

68 s+= matrix[rc -1][cc];

s+= matrix[rc -1][cc+1];

70 s+= matrix[rc][cc -1];

s+= matrix[rc][cc+1];

72 s+= matrix[rc+1][cc -1];

s+= matrix[rc+1][cc];

74 s+= matrix[rc+1][cc+1];

printf("sum (%2d, %2d)=%2.0f\n", rc , cc , s);

76 return s;

78 void manipolazione(FILE *dev)

80 int i, j;

fprintf(dev , "%d %d\n", r, c);

82 fprintf(dev , "%.1f ", sum(1, 1)/3);

for(j=2; j<c; j++)

84 fprintf(dev , "%.1f ", sum(1, j)/5);

if(j!=2)

86 fprintf(dev , "%.1f\n", sum(1, j)/3);

for(i=2; i<r; i++)

88

fprintf(dev , "%.1f ", sum(i, 1)/5);

90 for(j=2; j<c; j++)

fprintf(dev , "%.1f ", sum(i, j)/8);

92 if(j!=2)

fprintf(dev , "%.1f\n", sum(i, j)/5);

94

if(i!=2)

96

fprintf(dev , "%.1f ", sum(i, 1)/3);

98 for(j=2; j<c; j++)

fprintf(dev , "%.1f ", sum(i, j)/5);

100 if(j!=2)

fprintf(dev , "%.1f\n", sum(i, j)/3);

102

Listing 4.3: Manipolazione di una matrice - III

Tale implementazione, a differenza della precedente, evita il controllo per ogni casella, semplicementemettendo un bordo esterno alla matrice. Si avra un’utilizzo maggiore della memoria ma una riduzioneevidente degli if da valutare.

4.3 Esercizio n. 3: riformattazione di un testo

Un file contiene un testo di lunghezza indefinita. Si desidera un programma C che riformatti tale testomediante le regole seguenti:

• rimozione di tutti i caratteri di spaziatura

• trasformazione di tutti i caratteri alfabetici che si trovano dopo un carattere di spaziatura nelcarattere maiuscolo corrispondente, e degli altri nel corrispondente minuscolo

• riduzione della lunghezza delle righe del testo a 20 caratteri ciascuna (l’ultima puo ovviamenteessere piu corta)

Il testo cosı codificato venga scritto su un file di uscita.

60

Page 69: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

#include <stdio.h>

2 #include <stdlib.h>

#define path_in "text.txt"

4 #define path_out "text_out.txt"

#define row_lenght 20

6 char toLower(char c)

8 if(c>=’A’ && c<=’Z’)

return ’a’ + c - ’A’;

10 else

return c;

12

char toUpper(char c)

14

if(c>=’a’ && c<=’z’)

16 return ’A’ + c - ’a’;

else

18 return c;

20 int main()

22 FILE *fin , *fout;

char c, c_prec;

24 int c_write;

if((fin = fopen(path_in , "r"))==NULL)

26

printf("Il file %s non e’ stato aperto .\n", path_in);

28 system("pause");

return 1;

30

if((fout = fopen(path_out , "w"))==NULL)

32

printf("Il file %s non e’ stato aperto .\n", path_out);

34 system("pause");

return 2;

36

c_prec = ’ ’;

38 c_write = 0;

while ((c = fgetc(fin))!=EOF)

40

if(c!=’ ’)

42

if(c_prec ==’ ’)

44 fprintf(fout , "%c", toUpper(c));

else

46 fprintf(fout , "%c", toLower(c));

c_write ++;

48 if(c_write == row_lenght)

50 c_write =0;

fprintf(fout , "\n");

52

54 c_prec = c;

56 return 0;

Listing 4.4: Riformattazione di un testo

61

Page 70: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

62

Page 71: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Capitolo 5

Esercitazione 2

5.1 Esercizio n. 1: decompressione di un testo

Un’applicazione per la compressione di testi funziona in questo modo:

• Dato un file di testo, l’applicazione individua anzitutto un’insieme di parole del testo (tipicamentelunghe e ripetute) che verranno poi elaborate come segue.

• A ciascuna delle parole dell’insieme cosı costruito viene associato un intero univoco, con valoresempre compreso nell’intervallo [0 - 99]. L’applicazione riporta in un secondo file di testo ogniassociazione intero/parola (una per riga).

• Nel file di testo originale, infine, ogni parola che appartiene all’insieme viene sostituita dall’interoad essa associato (preceduto dal carattere $).

Si desidera un programma C che, dati due file (il file di testo trasformato e il corrispondente file delleassociazioni), ricostruisca il file di testo originale. Si puo assumere che ogni riga del file “compresso” sialunga al piu 80 caratteri.

Suggerimento: si usi un vettore di stringhe (realizzato come matrice di caratteri) per memorizzarel’associazione tra un intero (indice del vettore, ovvero indice di riga della matrice) e la parola (elementodel vettore, corrispondente a una riga della matrice) ad esso collegata. Il file di ingresso, inoltre, sia lettoper righe.

1 #include <stdio.h>

#include <string.h>

3 #include <stdlib.h>

#define ROWLENGHT 80

5 #define MAXINDEX 99

int decomprimi(char *filename_input , char *filename_output , char corr [][

ROWLENGHT +1]);

7 int leggi_corrispondenze(char *filename , char corr [][ ROWLENGHT +1]);

int main()

9

char corrispondenze[MAXINDEX +1][ ROWLENGHT +1];

11 if(! leggi_corrispondenze("corr.txt", corrispondenze))

13 printf("Errore apertura file delle corrispondenze .\n");

system("pause");

15 return -1;

17 if(! decomprimi("compressed.txt", "extracted.txt", corrispondenze))

19 printf("Errore in decompressione .\n");

system("pause");

21 return -2;

23 return 0;

63

Page 72: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

25 int decomprimi(char *filename_input , char *filename_output , char corr [][

ROWLENGHT +1])

27 FILE *fin , *fout;

char c;

29 int num_c , corrispondenza;

if((fin=fopen(filename_input , "r"))==NULL || (fout=fopen(

filename_output , "w"))==NULL)

31 return 0;

corrispondenza = 0;

33 while(fscanf(fin , "%c", &c)!=EOF)

35 if(c==’$’)

37 fscanf(fin , "%d", &num_c);

printf("%s", corr[num_c]);

39

else

41 printf("%c", c);

43 return 1;

45 int leggi_corrispondenze(char *filename , char corr [][ ROWLENGHT +1])

47 FILE *f;

int n_c;

49 for(n_c=0; n_c <MAXINDEX +1; n_c++)

corr[n_c ][0]=0;

51 if((f=fopen(filename , "r"))==NULL)

return 0;

53 while(fscanf(f, "%d", &n_c) != EOF)

fscanf(f, "%s", corr[n_c]);

55 fclose(f);

return 1;

57 Listing 5.1: Decompressione di un testo

5.2 Esercizio n. 2: stringhe periodiche.

Si scriva un programma in grado di:

• leggere da tastiera un numero indefinito di stringhe, ciascuna composta da soli caratteri alfanumericie di lunghezza massima pari a 30. La lettura termini quando viene introdotta la parola “stop”.

• indicare, per ciascuna stringa acquisita, se essa e “periodica” oppure no, ovvero costituita da un’u-nica sotto-stringa che si ripete. Ad esempio, sono periodiche (con periodo indicato tra parentesi)le seguenti sotto-stringhe: “zzzzz” (1), “k21k21” (3), “vivaviva” (4), etc. Si noti che una stringacomposta da un solo carattere, come anche una stringa in cui l’ultimo periodo non risulti concluso,non deve essere considerata periodica.

#include <stdio.h>

2 #include <stdlib.h>

#include <ctype.h>

4 #include <string.h>

#define terminatore "stop"

6 #define LENGHTMAX 30

int periodo(char str[]);

8 int main()

10 char str[LENGHTMAX +1]=0;

64

Page 73: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

int i, p, err =0;

12 do

14 printf("Stringa (%s per terminare)?\t", terminatore);

scanf("%s", str);

16 if(strcmp(str , terminatore)==0)

continue;

18 for(i=0; str[i]!=’\0’; i++)

if(! isalnum(str[i]))

20 err=1;

if(err)

22

err=0;

24 continue;

26 printf("La stringa %s", str);

p = periodo(str);

28 if(p>=1)

printf(" e’ periodica (periodo %d).\n", p);

30 else

printf(" non e’ periodica .\n");

32

while(strcmp(str , terminatore)!=0);

34 return 0;

36 int egualNcharacter(char s1[], char s2[], int n)

38 int i;

i=0;

40 while (*(s1+i)==*(s2+i) && *(s1+i)!=’\0’ && i<n)

i++;

42 return i==n;

44 int periodo(char str[])

46 int i, j;

int lenstr=strlen(str);

48 if(lenstr ==1 || lenstr == LENGHTMAX)

return 0;

50 for(i=1; i<= lenstr /2; i++)

52 if(lenstr%i==0)

54 for(j=i; j<lenstr && egualNcharacter(str , str+j, i); j+=i)

;

56 if(j== lenstr)

return i;

58

60 return 0;

Listing 5.2: Stringhe periodiche

5.3 Esercizio n. 3: voli aerei

Ogni riga di un file di testo descrive un volo aereo, nel formato:

<sigla_partenza> <sigla_arrivo>

in cui le sigle sono stringhe di tre caratteri (senza spazi) che identificano gli aeroporti di partenza e diarrivo. Supponendo che sia specificato un massimo di 200 voli, si scriva un programma che:

65

Page 74: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

• legga tale file (di nome predefinito), memorizzandone il contenuto in un’opportuna struttura dati.

• indichi sul video quali e quante sono le tratte aeree per le quali esistono sia il volo di andata chequello di ritorno.

#include <stdio.h>

2 #include <stdlib.h>

#include <string.h>

4 #define SIGLA_LENGHT 3

#define MAX_FLIGHT 200

6 #define flight_file "voli.txt"

typedef struct flight_t

8

char departure[SIGLA_LENGHT +1], arrival[SIGLA_LENGHT +1];

10 flight;

int leggi_voli(char *filename , flight voli[], int *n_voli);

12 void elabora_info(flight voli[], int n_voli);

int main()

14

flight voli[MAX_FLIGHT ];

16 int n_voli;

if(! leggi_voli(flight_file , voli , &n_voli))

18

printf("Errore nella lettura del file %s\n", flight_file);

20 system("pause");

return 1;

22

elabora_info(voli , n_voli);

24 system("pause");

return 0;

26

int leggi_voli(char *filename , flight voli[], int *n_voli)

28

FILE *f;

30 if((f=fopen(filename , "r"))==NULL)

return 0;

32 *n_voli = 0;

while (*n_voli <MAX_FLIGHT && fscanf(f, "%s %s", voli[* n_voli ].

departure , voli[* n_voli ]. arrival)==2)

34 *n_voli +=1;

fflush(f);

36 fclose(f);

return 1;

38

void elabora_info(flight voli[], int n_voli)

40

int i, j, ar=0;

42 for(i=0; i<n_voli -1; i++)

44 if(voli[i]. arrival [0]==0)

continue;

46 for(j=i+1; j<n_voli; j++)

48 if(voli[j]. arrival [0]==0)

continue;

50 if(strcmp(voli[i].departure , voli[j]. arrival)==0 && strcmp(

voli[i].arrival , voli[j]. departure)==0)

52 ar++;

printf("%s %s\n", voli[i].departure , voli[i]. arrival);

54 voli[j]. arrival [0] = voli[j]. departure [0] = 0;

66

Page 75: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

56

58 printf("Totale connessioni A/R: %d\n", ar);

Listing 5.3: Voli aerei

67

Page 76: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

68

Page 77: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Capitolo 6

Esercitazione 3

6.1 Esercizio n. 1: confronto tra algoritmi di ordinamento

Si realizzi un programma che:

• legga due numeri interi positivi M ed N .

• generi casualmente N numeri interi, memorizzandoli in un vettore allocato dinamicamente.

• ordini tale vettore in maniera crescente, utilizzando uno dei seguenti algoritmi:

– insertion sort

– selection sort

– bubble sort

ripeta la generazione casuale e l’ordinamento per M volte.

Si confrontino le prestazioni dei tre algoritmi per i valori diM = 10, 100, 1000 e diN = 1000, 5000, 10000,misurandone i tempi di esecuzione.

1 #include <stdio.h>

#include <stdlib.h>

3 #include <time.h>

#define VMAX RAND_MAX

5 int *my_alloca(int n_el);

void genera_casuale(int *vet , int n_el , int v_max);

7 void insersion_sort(int *vet , int dim);

void bubble_sort(int *vet , int dim);

9 void selection_sort(int *vet , int dim);

int is_ordinato(int *vet , int dim);

11 int main()

13 int *a;

int t0 , t1;

15 int i, j, M;

int vN[] = 1000 , 5000, 10000;

17 int vM[] = 10, 100, 1000;

printf(" N M insersion_sort bubble_sort selection_sort\n");

19 for(i=0; i<sizeof(vN)/sizeof(int); i++)

21 a = my_alloca(vN[i]);

for(j=0; j<sizeof(vM)/sizeof(int); j++)

23

printf("%6d %6d ", vN[i], vM[j]);

25 t0 = clock();

for(M=0; M<vM[j]; M++)

27

genera_casuale(a, vN[i], VMAX);

29 insersion_sort(a, vN[i]);

69

Page 78: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

31 t1 = clock ();

printf("%14.3f ", (( float)(t1 -t0))/CLOCKS_PER_SEC);

33 t0 = clock ();

for(M=0; M<vM[j]; M++)

35

genera_casuale(a, vN[i], VMAX);

37 bubble_sort(a, vN[i]);

39 t1 = clock ();

printf("%11.3f ", (( float)(t1 -t0))/CLOCKS_PER_SEC);

41 t0 = clock ();

for(M=0; M<vM[j]; M++)

43

genera_casuale(a, vN[i], VMAX);

45 selection_sort(a, vN[i]);

47 t1 = clock ();

printf("%14.3f ", (( float)(t1 -t0))/CLOCKS_PER_SEC);

49 printf("\n");

51 free(a);

53 system("pause");

return 0;

55

int *my_alloca(int n_el)

57

int *vet;

59 vet = (int *) malloc(n_el*sizeof(int));

return vet;

61

void genera_casuale(int *vet , int n_el , int v_max)

63

for(n_el --; n_el >=0; n_el --)

65

vet[n_el] = rand()%v_max;

67

69 void insersion_sort(int *vet , int dim)

71 int i, j, temp;

for(i=1; i<dim; i++)

73

temp = vet[i];

75 for(j=i-1; j>=0 && temp <vet[j]; j--)

77 vet[j+1] = vet[j];

79 vet[j+1]= temp;

81

void bubble_sort(int *vet , int dim)

83

int i, j, temp , scambio;

85 scambio =1;

for(i=dim -1; i>1 && scambio; i--)

87

scambio =0;

89 for(j=0; j<i; j++)

91 if(vet[j]>vet[j+1])

70

Page 79: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

93 temp = vet[j];

vet[j] = vet[j+1];

95 vet[j+1] = temp;

scambio =1;

97

99

101 void selection_sort(int *vet , int dim)

103 int i, j, temp , min;

for(i=0; i<dim -2; i++)

105

min=i;

107 for(j=i+1; j<dim -1; j++)

109 if(vet[j]<vet[min])

111 min = j;

113

if(min!=i)

115

temp = vet[i];

117 vet[i] = vet[min];

vet[min] = temp;

119

121

int is_ordinato(int *vet , int dim)

123

int i;

125 for(i=1; i<dim; i++)

if(vet[i]<vet[i-1])

127 return 0;

return 1;

129 Listing 6.1: Confronto degli algoritmi di ordinamento

6.2 Esercizio n. 2: ordinamento di stringhe

Un file di testo contiene un numero indefinito di stringhe, ciascuna di lunghezza massima pari a 30caratteri, una stringa per ogni riga del file. Si scriva un programma C che:

• acquisisca le stringhe contenute nel file di ingresso, memorizzandole in un vettore.

• ordini tale vettore mediante uno degli algoritmi di ordinamento noti.

• scriva il vettore ordinato su un secondo file di testo.

Si realizzi il programma in almeno due versioni:

1. facendo uso di una matrice statica di caratteri per memorizzare le stringhe del file di ingresso(assumendo che queste siano in numero al piu pari a 100).

2. allocando dinamicamente il vettore in cui salvare le stringhe e le stesse stringhe all’atto dellamemorizzazione.

Si noti che nel primo caso lo “scambio” tra due stringhe ai fini dell’ordinamento deve essere eseguitotramite delle opportune chiamate alla funzione strcpy(), mentre nel secondo occorre solo scambiare irelativi puntatori.

71

Page 80: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

#include <stdio.h>

2 #include <stdlib.h>

#include <string.h>

4 #define path_in "testo.txt"

#define path_out "testo1.txt"

6 #define lenMax 30

#define strMax 100

8 int leggi_file(char *path , char matrix [][ lenMax +1], int *n_stringhe);

int salva_file(char *path , char vet[][ lenMax +1], int dim);

10 void swap(char mat [][ lenMax +1], int i, int j);

void bubble_sort(char vet [][ lenMax +1], int dim);

12 void ordina(char mat [][ lenMax +1], int n_str);

int main()

14

int n_str;

16 char mat[strMax ][ lenMax +1];

if(! leggi_file(path_in , mat , &n_str))

18

printf("Errore in apertura del file %s.\n", path_in);

20 system("pause");

return 1;

22

ordina(mat , n_str);

24 if(! salva_file(path_out , mat , n_str))

26 printf("Errore in apertura del file %s.\n", path_out);

system("pause");

28 return 1;

30 system("pause");

return 0;

32

int leggi_file(char *path , char matrix [][ lenMax +1], int *n_stringhe)

34

FILE *f;

36 *n_stringhe =0;

if((f=fopen(path , "r"))==NULL)

38 return 0;

while(fscanf(f, "%s", matrix [* n_stringhe ])!=EOF)

40 *n_stringhe +=1;

return 1;

42

int salva_file(char *path , char vet[][ lenMax +1], int dim)

44

FILE *f;

46 if((f=fopen(path , "w"))==NULL)

return 0;

48 int i;

for(i=0; i<dim; i++)

50 fprintf(f, "%s\n", vet[i]);

fflush(f);

52 fclose(f);

return 1;

54

void swap(char mat [][ lenMax +1], int i, int j)

56

char temp[lenMax +1];

58 strcpy(temp , mat[i]);

strcpy(mat[i], mat[j]);

60 strcpy(mat[j], temp);

72

Page 81: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

62 void bubble_sort(char vet [][ lenMax +1], int dim)

64 int i, j, scambio;

scambio =1;

66 for(i=dim -1; i>1 && scambio; i--)

68 scambio =0;

for(j=0; j<i; j++)

70

if(strcmp(vet[j], vet[j+1]) >0)

72

swap(vet , j, j+1);

74 scambio =1;

76

78

void ordina(char mat [][ lenMax +1], int n_str)

80

bubble_sort(mat , n_str);

82 Listing 6.2: Ordinamento di stringhe con allocazione statica

1 #include <stdio.h>

#include <stdlib.h>

3 #include <string.h>

#define path_in "testo.txt"

5 #define path_out "testo1.txt"

#define lenMax 30

7 char ** leggi_file(char *path , int *n_stringhe);

void swap(char **mat , int i, int j);

9 void ordina(char **mat , int n_str);

void bubble_sort(char **vet , int dim);

11 int salva_file(char *path , char **vet , int dim);

int main()

13

int n_str;

15 char **mat = leggi_file(path_in , &n_str);

if(mat==NULL)

17

printf("Errore in apertura del file %s.\n", path_in);

19 system("pause");

return 1;

21

ordina(mat , n_str);

23 if(! salva_file(path_out , mat , n_str))

25 printf("Errore in apertura del file %s.\n", path_out);

system("pause");

27 return 1;

29 free(mat);

system("pause");

31 return 0;

33 char ** leggi_file(char *path , int *n_stringhe)

35 FILE *f;

char ** matrix;

37 matrix = NULL;

*n_stringhe =0;

73

Page 82: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

39 if((f=fopen(path , "r"))==NULL)

return matrix;

41 *n_stringhe =1;

matrix = (char **) malloc(sizeof(char *));

43 matrix [0] = (char *) malloc(lenMax*sizeof(char));

while(fscanf(f, "%s", matrix [*n_stringhe -1])!=EOF)

45

*n_stringhe +=1;

47 matrix = (char **) realloc(matrix , *n_stringhe*sizeof(char*));

matrix [* n_stringhe -1] = (char *) malloc(lenMax*sizeof(char));

49

fclose(f);

51 *n_stringhe -=1;

return matrix;

53

void swap(char **mat , int i, int j)

55

char *a;

57 a = mat[i];

mat[i] = mat[j];

59 mat[j] = a;

61 void ordina(char **mat , int n_str)

63 bubble_sort(mat , n_str);

65 void bubble_sort(char **vet , int dim)

67 int i, j, scambio;

scambio =1;

69 for(i=dim -1; i>1 && scambio; i--)

71 scambio =0;

for(j=0; j<i; j++)

73

if(strcmp(vet[j], vet[j+1]) >0)

75

swap(vet , j, j+1);

77 scambio =1;

79

81

int salva_file(char *path , char **vet , int dim)

83

FILE *f;

85 if((f=fopen(path , "w"))==NULL)

return 0;

87 int i;

for(i=0; i<dim; i++)

89 fprintf(f, "%s\n", vet[i]);

fflush(f);

91 fclose(f);

return 1;

93 Listing 6.3: Ordinamento di stringhe con allocazione dinamica

74

Page 83: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Capitolo 7

Esercitazione 4

7.1 Esercizio n. 1: occorrenze di parole

Si scriva un programma in grado di contare le occorrenze di ogni parola, appartenente a un insiemespecificato, all’interno di un generico testo.Piu in dettaglio, l’elenco delle parole da ricercare e memorizzato in un file di testo, in ragione di unaparola per riga del file. La lunghezza delle singole parole e limitata a 20 caratteri, e inoltre il numerototale di tali parole e indicato sulla prima riga del file stesso.Le parole cosı specificate devono essere ricercate in un testo memorizzato in un secondo file. Il numerodi righe di questo file e indefinito, ma si puo assumere che la lunghezza di ogni riga sia al piu pari a 100caratteri.Come output, il programma deve riportare su video l’elenco delle parole contenute nel primo file, ciascunaseguita dal numero di occorrenze con cui compare nel testo contenuto nel secondo file. Si noti che i duefile devono essere letti una volta sola.Si trascurino i possibili problemi derivanti dall’uso della punteggiatura (ovvero si considerino le stringhe“parola”, “parola.”, “parola!”, etc., come diverse).

POSSIBILE VARIANTE Si trattino le lettere maiuscole e quelle minuscole come equivalenti (ovvero,si considerino le stringhe “parola”, “PAROLA”, “ParolA”, etc., come corrispondenti).#include <stdio.h>

2 #include <stdlib.h>

#include <string.h>

4 #include <ctype.h>

#define occorrenze_path "ricercare.txt"

6 #define file_path "file.txt"

#define max_word_lenght 20

8 #define VARIANTE 1

struct occorrenze

10

char *word;

12 int number;

;

14 struct occorrenze *read_words(char *path , int *n_w);

int ricerca(char *el , struct occorrenze *list , int n_w);

16 void update_occorrenze(struct occorrenze *list , int n_w , char *path);

void print_occorrenze(struct occorrenze *list , int n_w);

18 void toLower(char *str);

int main()

20

struct occorrenze *words;

22 int n_words;

words = read_words(occorrenze_path , &n_words);

24 update_occorrenze(words , n_words , file_path);

print_occorrenze(words , n_words);

26 system("pause");

return 0;

28

75

Page 84: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

struct occorrenze *read_words(char *path , int *n_w)

30

*n_w=0;

32 struct occorrenze *list;

int i;

34 char tmp[max_word_lenght +1];

FILE *f;

36 if((f=fopen(path , "r"))==NULL)

return NULL;

38 fscanf(f, "%d", n_w);

list = (struct occorrenze *) malloc ((* n_w)*sizeof(struct occorrenze))

;

40 for(i=0; i<*n_w; i++)

42 list[i]. number =0;

fscanf(f, "%s", tmp);

44 list[i].word = strdup(tmp);

if(VARIANTE)

46 toLower(list[i].word);

48 fclose(f);

return list;

50

void update_occorrenze(struct occorrenze *list , int n_w , char *path)

52

FILE *f;

54 if((f=fopen(path , "r"))==NULL)

;

56 char *t;

int n_occorrenza;

58 t = (char *) malloc(max_word_lenght*sizeof(char));

while(fscanf(f, "%s", t)!=EOF)

60

n_occorrenza = ricerca(t, list , n_w);

62 if(n_occorrenza !=-1)

list[n_occorrenza ]. number ++;

64

fclose(f);

66

int ricerca(char *el , struct occorrenze *list , int n_w)

68

int i;

70 if(VARIANTE)

toLower(el);

72 for(i=0; i<n_w; i++)

74 if(strcmp(el , list[i].word)==0)

return i;

76

return -1;

78

void print_occorrenze(struct occorrenze *list , int n_w)

80

int i;

82 for(i=0; i<n_w; i++)

printf("%s - %d occorrenz%c\n", list[i].word , list[i].number , (

list[i]. number ==1 ? ’a’ : ’e’));

84

void toLower(char *str)

86

int i;

88 for(i=0; str[i]!=0; i++)

76

Page 85: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

str[i] = tolower(str[i]);

90 Listing 7.1: Occorrenza di parole

7.2 Esercizio n. 2: indice analitico

Si completi il codice ottenuto dall’esercizio precedente in maniera tale che, oltre al numero di occorrenze, ilprogramma visualizzi anche le posizioni (intese come numero d’ordine all’interno delle stringhe contenutenel testo, numerate progressivamente a partire da 1) in cui le parole specificate dal primo file sono staterintracciate nel secondo file.Si considerino due casi:

1. il programma limiti la visualizzazione di tali posizioni alle prime 10 occorrenze di ciascuna parola(qualora una stringa venisse rintracciata piu di 10 volte, il programma fornisca il conteggio esattodelle occorrenze, ma riporti solo le prime 10 posizioni)

2. il programma visualizzi correttamente tutte le posizioni in cui ogni parola del primo file appare nelsecondo

Si noti che nel primo caso e sufficiente utilizzare, per ciascuna parola da rintracciare, un vettore statico, ilcui contenuto puo essere generato durante la stessa fase di conteggio delle occorrenze. Nel secondo caso,invece, a meno di ricorrere a qualche altra struttura dati, si deve utilizzare un vettore dinamico, allocatoe “riempito” solo dopo aver trovato il numero di occorrenze di ciascuna parola.

1 #include <stdio.h>

#include <stdlib.h>

3 #include <string.h>

#include <ctype.h>

5 #define occorrenze_path "ricercare.txt"

#define file_path "file.txt"

7 #define max_word_lenght 20

#define VARIANTE 1

9 #define limita_indice 10

struct occorrenze

11

char *word;

13 int number , n_index;

int *indice;

15 ;

struct occorrenze *read_words(char *path , int *n_w);

17 int ricerca(char *el , struct occorrenze *list , int n_w);

void update_occorrenze(struct occorrenze *list , int n_w , char *path);

19 void print_occorrenze(struct occorrenze *list , int n_w);

void toLower(char *str);

21 int main()

23 struct occorrenze *words;

int n_words;

25 words = read_words(occorrenze_path , &n_words);

update_occorrenze(words , n_words , file_path);

27 print_occorrenze(words , n_words);

system("pause");

29 return 0;

31 struct occorrenze *read_words(char *path , int *n_w)

33 *n_w=0;

struct occorrenze *list;

35 int i;

char tmp[max_word_lenght +1];

37 FILE *f;

77

Page 86: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

if((f=fopen(path , "r"))==NULL)

39 return NULL;

fscanf(f, "%d", n_w);

41 list = (struct occorrenze *) malloc ((* n_w)*sizeof(struct occorrenze))

;

for(i=0; i<*n_w; i++)

43

list[i]. number =0;

45 list[i]. n_index =0;

list[i]. indice=NULL;

47 fscanf(f, "%s", tmp);

list[i].word = strdup(tmp);

49 if(VARIANTE)

toLower(list[i].word);

51

fclose(f);

53 return list;

55 void update_occorrenze(struct occorrenze *list , int n_w , char *path)

57 FILE *f;

if((f=fopen(path , "r"))==NULL)

59 ;

char *t;

61 int n_occorrenza , n_word =0;

t = (char *) malloc(max_word_lenght*sizeof(char));

63 while(fscanf(f, "%s", t)!=EOF)

65 n_word ++;

n_occorrenza = ricerca(t, list , n_w);

67 if(n_occorrenza !=-1)

69 list[n_occorrenza ]. number ++;

if(limita_indice >0)

71

if(list[n_occorrenza ]. n_index != limita_indice)

73

list[n_occorrenza ]. n_index ++;

75 list[n_occorrenza ]. indice = (int *) realloc(list[

n_occorrenza ].indice , (list[n_occorrenza ]. n_index

)*sizeof(int));

list[n_occorrenza ]. indice[list[n_occorrenza ].n_index

-1] = n_word;

77

79 else

81 list[n_occorrenza ]. n_index ++;

list[n_occorrenza ]. indice = (int *) realloc(list[

n_occorrenza ].indice , (list[n_occorrenza ]. n_index)*

sizeof(int));

83 list[n_occorrenza ]. indice[list[n_occorrenza ].n_index -1]

= n_word;

85

87 fclose(f);

89 int ricerca(char *el , struct occorrenze *list , int n_w)

91 int i;

if(VARIANTE)

78

Page 87: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

93 toLower(el);

for(i=0; i<n_w; i++)

95

if(strcmp(el , list[i].word)==0)

97 return i;

99 return -1;

101 void print_occorrenze(struct occorrenze *list , int n_w)

103 int i, j;

for(i=0; i<n_w; i++)

105

printf("%s - %d occorrenz%c", list[i].word , list[i].number , (

list[i]. number ==1 ? ’a’ : ’e’));

107 if(list[i].n_index >0)

109 printf("parol%c:", (list[i]. n_index ==1 ? ’a’ : ’e’));

for(j=0; j<list[i]. n_index; j++)

111 printf(" %d", list[i]. indice[j]);

113 printf("\n");

115

void toLower(char *str)

117

int i;

119 for(i=0; str[i]!=0; i++)

str[i] = tolower(str[i]);

121 Listing 7.2: Occorrenze parole con indice analitico

7.3 Esercizio n. 3: prodotto di matrici

Due matrici di interi (m1 e m2) sono memorizzate in due file con formato identico:

• la prima riga del file contiene le dimensioni (numero di righe r e di colonne c) della matrice

• le r righe successive contengono i c valori che appartengono alla riga corrente della matrice

Si scriva un programma che:

• acquisisca dinamicamente le due matrici, verificando che le loro dimensioni permettano di eseguireil prodotto m1 ·m2

• calcoli la matrice prodotto (allocando dinamicamente anch’essa)

• memorizzi tale matrice in un terzo file, con formato simile a quello di ingresso

I nomi dei tre file siano passati al programma sulla riga di comando.1 #include <stdio.h>

#include <stdlib.h>

3 struct matrix

5 int r, c;

int ** value;

7 ;

void read_matrix(struct matrix *mat , FILE *f);

9 void print_matrix(struct matrix mat , FILE *f);

int is_multiplicate(struct matrix mat1 , struct matrix mat2);

11 void multiplicate(struct matrix *result , struct matrix *mat1 , struct

matrix *mat2);

79

Page 88: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

int row_for_colums(struct matrix *mat1 , struct matrix *mat2 , int r, int

c);

13 int main(int argc , char *argv [])

15 if(argc <4)

17 printf("Parametri insufficienti: %s matrix1_file matrix2_file

result_file\n", argv [0]);

return EXIT_FAILURE;

19

FILE *f1, *f2, *f3;

21 if((f1=fopen(argv[1], "r"))==NULL)

23 printf("Errore apertura %s\n", argv [1]);

return EXIT_FAILURE;

25

if((f2=fopen(argv[2], "r"))==NULL)

27

printf("Errore apertura %s\n", argv [2]);

29 fclose(f1);

return EXIT_FAILURE;

31

if((f3=fopen(argv[3], "w"))==NULL)

33

printf("Errore apertura %s\n", argv [3]);

35 fclose(f1);

fclose(f2);

37 return EXIT_FAILURE;

39 struct matrix mat [3]=0;

read_matrix (&mat[0], f1);

41 read_matrix (&mat[1], f2);

if(is_multiplicate(mat[0], mat [1]))

43 multiplicate (&mat[2], &mat[0], &mat [1]);

print_matrix(mat[2], f3);+

45 fclose(f1);

fclose(f2);

47 fflush(f3);

fclose(f3);

49 return 0;

51 void read_matrix(struct matrix *mat , FILE *f)

53 fscanf(f, "%d %d", &mat ->r, &mat ->c);

mat ->value = (int **) malloc ((mat ->r)*sizeof(int *));

55 int i, j;

for(i=0; i<mat ->r; i++)

57

mat ->value[i] = (int *) malloc ((mat ->c)*sizeof(int));

59 for(j=0; j<mat ->c; j++)

fscanf(f, "%d", &mat ->value[i][j]);

61

63 void print_matrix(struct matrix mat , FILE *f)

65 fprintf(f, "%d %d\n", mat.r, mat.c);

int i, j;

67 for(i=0; i<mat.r; i++)

69 for(j=0; j<mat.c; j++)

fprintf(f, "%d ", mat.value[i][j]);

71 fprintf(f, "\n");

80

Page 89: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

73

int is_multiplicate(struct matrix mat1 , struct matrix mat2)

75

return mat1.c==mat2.r;

77

void multiplicate(struct matrix *result , struct matrix *mat1 , struct

matrix *mat2)

79

result ->r = mat1 ->r;

81 result ->c = mat2 ->c;

int i, j;

83 result ->value = (int **) malloc ((result ->r)*sizeof(int *));

for(i=0; i<result ->r; i++)

85

result ->value[i] = (int *) malloc ((result ->c)*sizeof(int));

87 for(j=0; j<result ->c; j++)

result ->value[i][j] = row_for_colums(mat1 , mat2 , i, j);

89

91 int row_for_colums(struct matrix *mat1 , struct matrix *mat2 , int r, int

c)

93 int res , i;

for(i=res =0; i<mat1 ->c; i++)

95 res+=mat1 ->value[r][i]*mat2 ->value[i][c];

return res;

97 Listing 7.3: Prodotto di matrici

81

Page 90: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

82

Page 91: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Capitolo 8

Esercitazione 5

8.1 Esercizio n. 1: Generazione di numeri binari.

Si realizzi un programma C che, acquisito da tastiera un numero N strettamente positivo, generi evisualizzi a video (mediante una funzione ricorsiva) tutti i numeri binari di N bit.

Vincoli e Restrizioni La generazione dei numeri binari deve essere ottenuta senza eseguire alcunaconversione di valori da decimale a binario.

Suggerimento Si utilizzi un vettore di N interi per rappresentare il numero binario (ogni elemento delvettore corrisponda a un bit del numero binario). La funzione ricorsiva deve, a ogni passo della ricorsione,assegnare il valore di uno dei bit del numero binario (si possono avere solo i casi 0 e 1). Per ognuno deidue possibili valori, si deve poi ricorrere per “sistemare” i bit successivi. Al termine della ricorsione,quindi, occorre visualizzare il numero cosı ottenuto.

1 #include <stdio.h>

#include <malloc.h>

3 #include <string.h>

void disposizioni(char *prefix , int n);

5 void stampa_disposizioni(int n);

int main()

7

int n;

9 printf("Inserisci il numero di bit:\t");

scanf("%d", &n);

11 stampa_disposizioni(n);

return 0;

13

void disposizioni(char *prefix , int n)

15

int s;

17 if(n==0)

printf("%s\n", prefix);

19 else

21 s = strlen(prefix);

prefix[s]=’0’;

23 prefix[s+1]=’\0’;

disposizioni(prefix , n-1);

25 prefix[s]=’1’;

prefix[s+1]=’\0’;

27 disposizioni(prefix , n-1);

29

void stampa_disposizioni(int n)

31

char *str;

33 if((str = (char *) malloc ((n+1)*sizeof(char)))==NULL)

83

Page 92: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

return ;

35 str [0]=’\0’;

disposizioni(str , n);

37 Listing 8.1: Generazione di numeri binari

8.2 Esercizio n. 2: Sviluppo di un sistema del totocalcio.

Un file di testo contiene la descrizione di un sistema relativo a una schedina del gioco del totocalcio. Ilfile e composto da N righe, in ognuna delle quali si possono trovare uno, due oppure tutti e tre i simboliper i possibili risultati (che sono 1, 2 e X). Si scriva un programma C che, acquisito il contenuto delfile in un’opportuna struttura dati interna, generi tutte le colonne della schedina appartenenti al sistemaletto, espandendo tutte le coppie e le triple di simboli e generando tutte le possibili combinazioni. Talicombinazioni siano, quindi, memorizzate in un secondo file, in ragione di una per riga.Si noti che il valore di N non e noto a priori, ne esso compare in alcun modo nel file di ingresso: talevalore deve essere opportunamente dedotto dal programma a partire dal contenuto del file stesso.

1 #include <stdio.h>

#include <string.h>

3 #include <malloc.h>

#define PATH "sistema.txt"

5 char ** contenuto_file(char *path , int *n_righe);

void stampa_colonne(char *path , char **file , int n_righe);

7 void genera_e_stampa(FILE *fp , char **file , int n_righe , char *str);

void print_reversed(char *str);

9 int main()

11 char **file;

int n_righe;

13 if((file = contenuto_file(PATH , &n_righe))==NULL)

return -1;

15 stampa_colonne("stdout", file , n_righe);

free(file);

17 return 0;

19 char ** contenuto_file(char *path , int *n_righe)

21 int i;

char **res , tmp [5];

23 FILE *f;

*n_righe =0;

25 if((f=fopen(path , "r"))==NULL)

return NULL;

27 for(; fgets(tmp , 5, f)!=NULL; (* n_righe)++)

;

29 rewind(f);

if((res=(char **) malloc ((* n_righe)*sizeof(char *)))==NULL)

31

*n_righe =0;

33 return NULL;

35 for(i=0; i<(* n_righe); i++)

37 fscanf(f, "%s", tmp);

res[i] = strdup(tmp);

39 if(res[i]== NULL)

41 for(i--; i>=0; i--)

free(res[i]);

43 free(res);

84

Page 93: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

*n_righe =0;

45 return NULL;

47

return res;

49

void stampa_colonne(char *path , char **file , int n_righe)

51

if(path==NULL || file == NULL || n_righe ==0)

53 return ;

FILE *fp;

55 char *str;

if((str = (char *) malloc (( n_righe +1)*sizeof(char)))==NULL)

57 return ;

if(strcmp(path , "stdout")==0)

59 fp = stdout;

else

61 if((fp=fopen(path , "w"))==NULL)

return;

63 str [0]=’\0’;

genera_e_stampa(fp, file , n_righe , str);

65 if(fp== stdout)

fclose(fp);

67 free(str);

69 void genera_e_stampa(FILE *fp , char **file , int n_righe , char *prefix)

71 if(n_righe ==0)

print_reversed(prefix);

73 else

75 int i, s = strlen(file[n_righe -1]), sp = strlen(prefix);

for(i=0; i<s; i++)

77

prefix[sp] = file[n_righe -1][i];

79 prefix[sp+1] = ’\0’;

genera_e_stampa(fp, file , n_righe -1, prefix);

81

83

void print_reversed(char *str)

85

int i;

87 for(i=strlen(str) -1; i>=0; i--)

printf("%c", str[i]);

89 printf("\n");

Listing 8.2: Sviluppo di un sistema del totocalcio

8.3 Esercizio n. 3: calcolo del determinante di una matrice.

Un file contiene una matrice quadrata di interi di lato N . Si scriva un programma in grado di leggere ilfile in questione e di calcolare il valore del determinante della matrice in esso contenuta, visualizzandotale valore sul video.Si ricorda che il determinante di una matrice quadrata di lato 1 coincide con il valore dell’unico ele-mento della matrice stessa, mentre, per valori superiori del “lato”, esso puo essere calcolato (in manieraequivalente) mediante una delle seguenti formule:

∆ =

N∑i=1

(−1)i+j ·mij ·∆ij j ∈ [1, N ] ∆ =

N∑i=1

(−1)i+j ·mij ·∆ij i ∈ [1, N ]

85

Page 94: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

essendo mij l’elemento della matrice in posizione [i, j] e ∆ij il determinante della matrice che si ottienecancellando la riga i e la colonna j dalla matrice di partenza.Si noti che il valore di N non e noto: esso deve essere dedotto dal contenuto del file di ingresso.#include <stdio.h>

2 #include <string.h>

#include <malloc.h>

4 #define PATH "matrice.txt"

float ** leggi_file(char *path , int *dim);

6 float determinante(float **matrice , int dim);

float ** complemento_algebrico(float **matrice , int dim , int r, int c);

8 int main()

10 float ** matrice;

int dim;

12 if(( matrice = leggi_file(PATH , &dim))==NULL)

return -1;

14 printf("Il determinante della matrice nel file e’ %f\n",

determinante(matrice , dim));

return 0;

16

float ** complemento_algebrico(float **matrice , int dim , int r, int c)

18

if(matrice ==NULL || r<0 || c<0 || r>=dim || c>=dim)

20 return NULL;

float ** complemento;

22 if(( complemento =( float **) malloc ((dim -1)*sizeof(float *)))==NULL)

return 0;

24 int i, j;

int in , jn;

26 for(i=in=0; i<dim; i++)

28 if(i!=dim -1)

if(( complemento[i]=( float *) malloc ((dim -1)*sizeof(float)))==

NULL)

30 return 0;

if(i==r)

32 continue;

for(j=jn=0; j<dim; j++)

34

if(j==c)

36 continue;

complemento[in][jn]= matrice[i][j];

38 jn++;

if(jn%(dim -1) ==0)

40

jn=0;

42 in++;

44

46 return complemento;

48 float determinante(float **matrice , int dim)

50 int i;

if(dim ==1)

52 return matrice [0][0];

float res=0;

54 float **mtemp;

for(i=0; i<dim; i++)

56

86

Page 95: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

mtemp = complemento_algebrico(matrice , dim , 0, i);

58 if(mtemp==NULL)

exit(EXIT_FAILURE);

60 if(i%2==0)

res+= matrice [0][i]* determinante(mtemp , dim -1);

62 else

res -= matrice [0][i]* determinante(mtemp , dim -1);

64 free(mtemp);

66 return res;

68 float ** leggi_file(char *path , int *dim)

70 float **mat;

FILE *fp;

72 *dim=0;

if((fp=fopen(path , "r"))==NULL)

74 return NULL;

int i, j;

76 char c;

while ((c=fgetc(fp))!=EOF)

78 if(c==’\n’)

(*dim)++;

80 rewind(fp);

if((mat = (float **) malloc ((* dim)*sizeof(float *)))==NULL)

82

fclose(fp);

84 return NULL;

86 for(i=0; i<(*dim); i++)

88 if((mat[i] = (float *) malloc ((* dim)*sizeof(float)))==NULL)

90 for(i--; i>=0; i--)

free(mat[i]);

92 free(mat);

return NULL;

94

for(j=0; j<(* dim); j++)

96 fscanf(fp , "%f", &mat[i][j]);

98 fclose(fp);

return mat;

100 Listing 8.3: Determinante di una matrice

87

Page 96: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

88

Page 97: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Capitolo 9

Esercitazione 6

9.1 Esercizio n. 1: Punti del piano.

Si scriva un programma che:

• acquisisca da file un numero indefinito di punti del piano cartesiano, memorizzandoli in un vettoredi strutture (“punto”) allocato dinamicamente. Le coordinate dei punti sono riportate nel file diingresso su righe consecutive, in ragione di una riga del file per punto cartesiano.

• determini:

– la coppia di punti piu vicini tra loro, visualizzandone le coordinate.

– la coppia di punti piu lontani tra loro, visualizzandone le coordinate.

– il numero di segmenti, ottenuti congiungendo due qualsiasi punti dell’insieme letto, che hannolunghezza inferiore a un valore d inserito dall’utente.

• ordini (mediante un algoritmo noto) i punti memorizzati nel vettore per valori crescenti di distanzadall’origine del piano. Il vettore cosı ordinato sia salvato su un file di uscita.

Vincoli e restrizioni Si richiede che il programma venga realizzato su piu file, con struttura modulare,come suggerito nel §3.1 del Sedgewick. Piu in dettaglio, si preveda un modulo per la gestione del tipo“punto”, composto da interfaccia e implementazione, contenente la dichiarazione del tipo stesso e lefunzioni base per operare su questo tipo di dato (ad esempio, per eseguire la lettura di un punto, calcolarela distanza tra due punti, visualizzare le coordinate di un dato punto, etc.), e un modulo “client” che,utilizzando tali funzioni, soddisfi le richieste dell’esercizio.#include <stdio.h>

2 #include "point.h"

#define path_in "punti.txt"

4 #define path_out "punti_ordinati.txt"

void vfree(point **lista , int n_punti);

6 point ** read_point_by_file(char *path , int *n_p);

int *coppia_minima_distanza(point **lista , int n_punti);

8 int *coppia_massima_distanza(point **lista , int n_punti);

int segmenti_distanza_minore(point **lista , int n_punti , float d);

10 int ordina(point **lista , int n_punti , char *path);

void quickSort(point **lista , int l, int r);

12 int partition(point **lista , int l, int r);

int main()

14

int *min , *max , n_segmenti;

16 point **lista;

int n_punti;

18 float d;

if((lista=read_point_by_file(path_in , &n_punti))==NULL)

20 return 1;

do

22

printf("Introduci il parametro d:\t");

89

Page 98: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

24 scanf("%f", &d);

while(d<=0);

26 if((min = coppia_minima_distanza(lista , n_punti))==NULL)

28 printf("Errore allocazione dimanica della memoria .\n");

vfree(lista , n_punti);

30

if((max = coppia_massima_distanza(lista , n_punti))==NULL)

32

printf("Errore allocazione dimanica della memoria .\n");

34 free(min);

vfree(lista , n_punti);

36

n_segmenti = segmenti_distanza_minore(lista , n_punti , d);

38 printf("La coppia dei punti piu’ vicini tra loro e’ composta dai

punti\n\t");

pPrint_to_stream(lista[min[0]], stdout);

40 printf("\n\t");

pPrint_to_stream(lista[min[1]], stdout);

42 printf("\n");

printf("La coppia dei punti piu’ lontani tra loro e’ composta dai

punti\n\t");

44 pPrint_to_stream(lista[max[0]], stdout);

printf("\n\t");

46 pPrint_to_stream(lista[max[1]], stdout);

printf("\n");

48 if(n_segmenti ==0)

printf("Non sono presenti segmenti con lunghezza inferiore a %f\

n", d);

50 else if(n_segmenti ==1)

printf("E’ presente un segmento con lunghezza inferiore a %f\n",

d);

52 else

printf("Sono presenti %d segmenti con lunghezza inferiore a %f\n

", n_segmenti , d);

54 ordina(lista , n_punti , path_out);

free(min);

56 free(max);

vfree(lista , n_punti);

58 return 0;

60 void vfree(point **lista , int n_punti)

62 int i;

for(i=0; i<n_punti; i++)

64 free(lista[i]);

free(lista);

66

point ** read_point_by_file(char *path , int *n_p)

68

FILE *f;

70 point **res;

char c;

72 int i;

*n_p=0;

74 if((f=fopen(path , "r"))==NULL)

76 printf("Errore lettura file di ingresso %s\n", path);

return NULL;

78

while ((c=fgetc(f))!=EOF)

80 if(c==’\n’)

90

Page 99: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

(*n_p)++;

82 if(*n_p ==0)

84 printf("Non sono presenti punti nel file.\n");

return NULL;

86

if((res = (point **) malloc ((* n_p)*sizeof(point *)))==NULL)

88

printf("Errore allocazione dinamica della memoria .\n");

90 fclose(f);

return NULL;

92

rewind(f);

94 for(i=0; i<(*n_p); i++)

if((res[i]= pRead_by_stream(f))==NULL)

96

printf("Errore allocazione dinamica della memoria .\n");

98 for(i--; i>=0; i--)

free(res[i]);

100 free(res);

return NULL;

102

return res;

104

int *coppia_minima_distanza(point **lista , int n_punti)

106

int i, j, *res;

108 double dmin=-1.0, dcorr;

if((res=(int *) malloc (2* sizeof(int)))==NULL)

110

printf("Errore allocazione dinamica della memoria .\n");

112 return NULL;

114 for(i=0; i<n_punti -1; i++)

for(j=i+1; j<n_punti; j++)

116

dcorr = pDistanza(lista[i], lista[j]);

118 if(dmin ==-1.0 || dcorr <dmin)

120 res[0] = i;

res[1] = j;

122 dmin = dcorr;

124

return res;

126

int *coppia_massima_distanza(point **lista , int n_punti)

128

int i, j, *res;

130 double dmax=-1.0, dcorr;

if((res=(int *) malloc (2* sizeof(int)))==NULL)

132

printf("Errore allocazione dinamica della memoria .\n");

134 return NULL;

136 for(i=0; i<n_punti -1; i++)

138 for(j=i+1; j<n_punti; j++)

140 dcorr = pDistanza(lista[i], lista[j]);

142 res[0] = i;

91

Page 100: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

res [1] = j;

144 dmax = dcorr;

146

148 return res;

150 int segmenti_distanza_minore(point **lista , int n_punti , float d)

152 d = d*d;

int i, j, res;

154 for(i=res=0; i<n_punti -1; i++)

for(j=i+1; j<n_punti; j++)

156

if((lista[i]->x-lista[j]->x)*( lista[i]->x-lista[j]->x)+(

lista[i]->y-lista[j]->y)*(lista[i]->y-lista[j]->y)<d)

158 res ++;

160 return res;

162 int ordina(point **lista , int n_punti , char *path)

164 FILE *f;

if((f=fopen(path , "w"))==NULL)

166

printf("Errore apertura file di output %s\n", path);

168 return 0;

170 quickSort(lista , 0, n_punti -1);

int i;

172 for(i=0; i<n_punti; i++)

174 pPrint_to_stream(lista[i], f);

fprintf(f, "\n");

176

fflush(f);

178 fclose(f);

return 1;

180

void quickSort(point **lista , int l, int r)

182

int p;

184 if(l<r)

186 p = partition(lista , l, r);

quickSort(lista , l, p);

188 quickSort(lista , p+1, r);

190

int partition(point **lista , int l, int r)

192

point *temp;

194 int i, j;

i = l-1;

196 j = r+1;

while(i<j)

198

while(pCompareModulo(lista [++i], lista[l]) <0)

200 ;

while(pCompareModulo(lista[--j], lista[l]) >0)

202 ;

if(i<j)

92

Page 101: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

204

temp = lista[i];

206 lista[i] = lista[j];

lista[j] = temp;

208

210 return j;

Listing 9.1: Punti del piano (client.c)

#include <malloc.h>

2 #include <math.h>

typedef struct point_t

4

float x, y;

6 point;

point *pRead_by_stream(FILE *stream);

8 point *pRead_by_string(char *str);

float pDistanza(point *p1, point *p2);

10 float pModulo(point *p);

int pCompareModulo(point *p1 , point *p2);

12 int pCompareModulo_con_riferimento(point *p1 , point *p2 , point *rif);

int pPrint_to_stream(point *p, FILE *f);

14 int pPrint_to_stream_with_precision(point *p, FILE *f, int cifre); Listing 9.2: Punti del piano (point.h)

1 #include <stdio.h>

#include "point.h"

3 point ORIGINE = 0, 0;

point *pRead_by_stream(FILE *stream)

5

if(stream ==NULL)

7 return NULL;

point *res;

9 if((res=malloc(sizeof(point)))==NULL)

return NULL;

11 fscanf(stream , "%f %f", &res ->x, &res ->y);

return res;

13

point *pRead_by_string(char *str)

15

if(str==NULL)

17 return NULL;

point *res;

19 if((res=malloc(sizeof(point)))==NULL)

return NULL;

21 sscanf(str , "%f %f", &res ->x, &res ->y);

return res;

23

float pDistanza(point *p1, point *p2)

25

double dx , dy;

27 dx = p1->x-p2->x;

dy = p1->y-p2->y;

29 return sqrt((dx*dx)+(dy*dy));

31 float pModulo(point *p)

33 return pDistanza(p, &ORIGINE);

93

Page 102: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

35 int pCompareModulo(point *p1 , point *p2)

37 return pModulo(p1)-pModulo(p2);

39 int pCompareModulo_con_riferimento(point *p1 , point *p2 , point *rif)

41 return pDistanza(p1 , rif)-pDistanza(p2 , rif);

43 int pPrint_to_stream(point *p, FILE *f)

45 return pPrint_to_stream_with_precision(p, f, 2);

47 int pPrint_to_stream_with_precision(point *p, FILE *f, int cifre)

49 if(f==NULL)

return 0;

51 fprintf(f, "%.*f %.*f", cifre , p->x, cifre , p->y);

return 1;

53 Listing 9.3: Punti del piano (point.c)

9.2 Esercizio n. 2: Ricerche dicotomiche.

Un file contiene un insieme di dati, in numero ignoto, di un generico tipo item. Supponendo che essirisultino ordinati, si scriva un programma modulare che, memorizzato il contenuto del file in un’opportunastruttura dati interna, permetta all’utente di effettuare delle ricerche dicotomiche.Piu in dettaglio, il programma deve essere composto da due moduli:

• l’interfaccia utente (il main), contenente anche la funzione di ricerca binaria.

• un modulo con le funzioni per la gestione di basso livello dei dati.

Si supponga che il tipo item possa essere (a scelta del programmatore):

• un numero intero.

• una stringa di lunghezza massima pari a 50 caratteri.

Vincoli e restrizioni Si richiede che il modulo dei dati contenga le funzioni per manipolare solo unsingolo dato (o, al piu, due dati nel caso del confronto), senza “sapere” che tali dati sono memorizzati inun vettore. Ad esempio, e illecito definire in questo modulo una funzione che esegua per intero la letturadel file di ingresso e restituisca il vettore contenente i dati. Tale operazione deve essere opportunamenteeseguita all’interno del modulo principale (il main).

1 #include <stdio.h>

#include <string.h>

3 #include "item.h"

#define path_file "item.txt"

5 #define MAX 10

void v_free(ITEM **lista , int n_item);

7 int binary_find(ITEM **lista , int l, int r, ITEM *el);

ITEM ** leggi_da_file(char *path , int *n_item);

9 int main()

11 int n_item , index , fine;

ITEM **lista , *iAtt;

13 char cmd[MAX];

if(( lista=leggi_da_file(path_file , &n_item))==NULL)

15 return 1;

fine =0;

17 while (!fine)

94

Page 103: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

19 scanf("%s", cmd);

if(strcmp(cmd , "find")==0)

21

iAtt = iRead_By_stream(stdin);

23 if(iAtt!=NULL)

25 index = binary_find(lista , 0, n_item -1, iAtt);

if(index ==-1)

27 printf("Elemento non trovato .\n");

else

29 printf("Elemento trovato in posizione %d.\n", index)

;

free(iAtt);

31

33 else if(strcmp(cmd , "exit")==0)

fine =1;

35 else

printf("Comando non riconosciuto .\n");

37

v_free(lista , n_item);

39 return 0;

41 void v_free(ITEM **lista , int n_item)

43 if(lista ==NULL)

return ;

45 for(n_item --; n_item >=0; n_item --)

free(lista[n_item ]);

47 free(lista);

49 int binary_find(ITEM **lista , int l, int r, ITEM *el)

51 int m;

if(l>r)

53 return -1;

m = (l+r)/2;

55 if(iCompare(el, lista[m])==0)

return m;

57 else if(iCompare(el , lista[m]) <0)

return binary_find(lista , l, m-1, el);

59 else

return binary_find(lista , m+1, r, el);

61

ITEM ** leggi_da_file(char *path , int *n_item)

63

FILE *f;

65 ITEM **res;

char c;

67 int i;

*n_item =0;

69 if(path==NULL)

return NULL;

71 if((f=fopen(path , "r"))==NULL)

73 printf("Errore apertura file.\n");

return NULL;

75

while ((c=fgetc(f))!=EOF)

77 if(c==’\n’)

(* n_item)++;

79 rewind(f);

95

Page 104: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

if(* n_item ==0)

81

printf("Non sono presenti item nel file %s\n", path);

83 fclose(f);

return NULL;

85

if((res=(ITEM **) malloc ((* n_item)*sizeof(ITEM *)))==NULL)

87

printf("Errore allocazione dinamica della memoria .\n");

89 *n_item = 0;

fclose(f);

91 return NULL;

93 for(i=0; i<(* n_item); i++)

95 res[i] = iRead_By_stream(f);

if(res[i]== NULL)

97

printf("Errore allocazione dinamica della memoria .\n");

99 for(i--; i>=0; i--)

free(res[i]);

101 free(res);

*n_item =0;

103 fclose(f);

return NULL;

105

107 fclose(f);

return res;

109 Listing 9.4: Ricerche dicotomiche (client.c)

1 #include <malloc.h>

typedef struct

3

int num;

5 ITEM;

ITEM *iRead_By_stream(FILE *stream);

7 ITEM *iRead_By_string(char *string);

int iPrint(ITEM *i, FILE *stream);

9 int iCompare(ITEM *i1 , ITEM *i2); Listing 9.5: Ricerche dicotomiche (item.h)

1 #include <stdio.h>

#include "item.h"

3 ITEM *iRead_By_stream(FILE *stream)

5 if(stream ==NULL)

return NULL;

7 ITEM *res;

if((res=(ITEM *) malloc(sizeof(ITEM)))==NULL)

9 return NULL;

fscanf(stream , "%d", &res ->num);

11 return res;

13 ITEM *iRead_By_string(char *string)

15 if(string ==NULL)

return NULL;

17 ITEM *res;

96

Page 105: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

if((res=(ITEM *) malloc(sizeof(ITEM)))==NULL)

19 return NULL;

sscanf(string , "%d", &res ->num);

21 return res;

23 int iPrint(ITEM *i, FILE *stream)

25 if(i==NULL || stream ==NULL)

return 0;

27 fprintf(stream , "%d", i->num);

return 1;

29

int iCompare(ITEM *i1 , ITEM *i2)

31

return i1 ->num -i2 ->num;

33 Listing 9.6: Ricerche dicotomiche (item.c)

9.3 Esercizio n. 3: Confronto tra algoritmi di ordinamento.

Si realizzi un programma modulare che:

• legga due numeri positivi M ed N .

• generi casualmente N dati, memorizzandoli in un vettore.

• ordini tale vettore in maniera “crescente”, utilizzando uno dei seguenti algoritmi:

– merge sort

– quick sort

– heap sort

• ripeta la generazione casuale e l’ordinamento per M volte.

Si confrontino le prestazioni dei tre algoritmi per i valori di M = 10, 100, 1000 e di N = 1000, 5000, 10000,misurandone i tempi di esecuzione. Si confrontino, inoltre, le prestazioni di tali algoritmi rispetto a quelledegli algoritmi iterativi.Il programma deve essere composto da tre moduli distinti:

• l’interfaccia utente (il main).

• un modulo contenente le funzioni di ordinamento.

• un modulo con le funzioni per la gestione di basso livello dei dati.

Si supponga che il tipo di dato base “item” memorizzato nel vettore possa essere (a scelta):

• una stringa di lunghezza massima pari a 50 caratteri.

• un numero intero.#include <stdio.h>

2 #include <time.h>

#include "sort.h"

4 void vfree(ITEM **lista , int n);

ITEM ** my_alloca(int n_el);

6 void genera_casuale(ITEM **vet , int n_el);

int main()

8

ITEM ** lista;

10 int t0 , t1;

int i, j, M;

12 int vN[] = 1000 , 5000, 10000;

97

Page 106: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

int vM[] = 10, 100, 1000;

14 printf(" N M merge_sort quick_sort\n");

for(i=0; i<sizeof(vN)/sizeof(int); i++)

16

lista = my_alloca(vN[i]);

18 for(j=0; j<sizeof(vM)/sizeof(int); j++)

20 printf("%6d %6d ", vN[i], vM[j]);

t0 = clock ();

22 for(M=0; M<vM[M]; M++)

24 genera_casuale(lista , vN[i]);

merge_sort(lista , 0, vN[i]-1);

26 vfree(lista , vN[i]);

28 t1 = clock ();

printf("%10.3f ", (( float)(t1 -t0))/CLOCKS_PER_SEC);

30 t0 = clock ();

for(M=0; M<vM[M]; M++)

32

genera_casuale(lista , vN[i]);

34 quick_sort(lista , 0, vN[i]-1);

vfree(lista , vN[i]);

36

t1 = clock ();

38 printf("%10.3f ", (( float)(t1 -t0))/CLOCKS_PER_SEC);

printf("\n");

40

42 free(lista);

system("pause");

44 return 0;

46 void vfree(ITEM **lista , int n)

48 if(lista==NULL)

return;

50 for(n--; n>=0; n--)

free(lista[n]);

52

ITEM ** my_alloca(int n_el)

54

ITEM **vet;

56 vet = (ITEM **) malloc(n_el*sizeof(ITEM *));

return vet;

58

void genera_casuale(ITEM **vet , int n_el)

60

for(n_el --; n_el >=0; n_el --)

62 vet[n_el] = iInit_rand ();

Listing 9.7: Confronto tra algoritmi di ordinamento (client.c)

1 #include <stdio.h>

#include <malloc.h>

3 typedef struct

5 int num;

ITEM;

7 ITEM *iRead_By_stream(FILE *stream);

ITEM *iRead_By_string(char *string);

98

Page 107: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

9 int iPrint(ITEM *i, FILE *stream);

int iCompare(ITEM *i1 , ITEM *i2);

11 int iCopy(ITEM *i1 , ITEM *i2);

ITEM *iInit_rand (); Listing 9.8: Confronto tra algoritmi di ordinamento (item.h)

#include <stdio.h>

2 #include <time.h>

#include "item.h"

4 #define __i_rand_max RAND_MAX

ITEM *iRead_By_stream(FILE *stream)

6

if(stream ==NULL)

8 return NULL;

ITEM *res;

10 if((res=(ITEM *) malloc(sizeof(ITEM)))==NULL)

return NULL;

12 fscanf(stream , "%d", &res ->num);

return res;

14

ITEM *iRead_By_string(char *string)

16

if(string ==NULL)

18 return NULL;

ITEM *res;

20 if((res=(ITEM *) malloc(sizeof(ITEM)))==NULL)

return NULL;

22 sscanf(string , "%d", &res ->num);

return res;

24

int iPrint(ITEM *i, FILE *stream)

26

if(i==NULL || stream ==NULL)

28 return 0;

fprintf(stream , "%d", i->num);

30 return 1;

32 int iCompare(ITEM *i1 , ITEM *i2)

34 return i1 ->num -i2 ->num;

36 int iCopy(ITEM *i1 , ITEM *i2)

38 if(i1==NULL || i2==NULL)

return 0;

40 *i1 = *i2;

return 1;

42

ITEM *iInit_rand ()

44

ITEM *res;

46 if((res = (ITEM *) malloc(sizeof(ITEM)))==NULL)

return NULL;

48 res ->num = rand() % __i_rand_max;

return res;

50 Listing 9.9: Confronto tra algoritmi di ordinamento (item.c)

#include "item.h"

2 int merge_sort(ITEM **vec , int l, int r);

99

Page 108: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

void quick_sort(ITEM **vec , int l, int r); Listing 9.10: Confronto tra algoritmi di ordinamento (sort.h)

#include "sort.h"

2 int Merge(ITEM **vec , int l, int m, int r)

4 int i, j, k;

ITEM **tmp;

6 if((tmp=(ITEM **) malloc ((r+1)*sizeof(ITEM*)))==NULL)

return 0;

8 i=l;

j=m+1;

10 k=l;

while(i<=m && j<=r)

12

if(iCompare(vec[i],vec[j]) <0)

14 tmp[k++] = vec[i++];

else

16 tmp[k++] = vec[j++];

18 while(i<=m)

tmp[k++] = vec[i++];

20 while(j<=r)

tmp[k++] = vec[j++];

22 for(k=l; k<=r; k++)

vec[k] = tmp[k];

24 return 1;

26 int merge_sort(ITEM **vec , int l, int r)

//add a return value because dynamic allocator can be falliure

28

int m;

30 if(l<r)

32 m = (l+r)/2;

merge_sort(vec , l, m);

34 merge_sort(vec , m+1, r);

Merge(vec , l, m, r);

36

return 1;

38

int partition(ITEM **vec , int l, int r)

40

int i, j;

42 ITEM *tmp;

i = l-1;

44 j = r+1;

while(i<j)

46

while(iCompare(vec[--j], vec[l]) >0)

48 ;

while(iCompare(vec[++i], vec[l]) <0)

50 ;

if(i<j)

52

tmp=vec[i];

54 vec[i] = vec[j];

vec[j] = tmp;

56

58 return j;

100

Page 109: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

60 void quick_sort(ITEM **vec , int l, int r)

62 int p;

if(l<r)

64

p = partition(vec , l, r);

66 quick_sort(vec , l, p);

quick_sort(vec , p+1, r);

68

Listing 9.11: Confronto tra algoritmi di ordinamento (sort.c)

101

Page 110: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

102

Page 111: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Capitolo 10

Esercitazione 7

10.1 Esercizio n. 1: gestione di strutture FIFO.

Si realizzi un programma C che, attraverso un’apposita interfaccia utente, permetta di gestire una strut-tura dati di tipo FIFO (coda non prioritaria).Le operazione permesse devono essere quelle di:

• creazione di una nuova struttura (vuota).

• inserimento di un nuovo elemento della struttura.

• estrazione di un elemento dalla struttura.

• visualizzazione (a video) di tutti gli elementi nella base dati (opzionale).

• salvataggio della base dati su file (opzionale).

• caricamento di una nuova base dati da file (opzionale).

In questo esercizio, il programma deve essere realizzato su tre moduli distinti:

• l’interfaccia utente (il client).

• un modulo con le funzioni per la gestione della coda.

• un modulo con le funzioni per la gestione dei singoli dati.

In particolare, si desidera che l’implementazione della libreria sulla struttura dati corrisponda a un ADTdi I categoria.Si supponga che ogni elemento della base dati possa essere (a scelta del programmatore):

• una stringa di lunghezza massima pari a 50 caratteri.

• un numero intero.

• una struttura composta da due campi (stringa + numero).

Si realizzi il programma in due versioni:

• supponendo che il numero massimo di elementi nella coda sia pari a 100 (implementazione tramitevettori).

• supponendo che non ci sia limite al numero di elementi che e possibile memorizzare nella coda(implementazione tramite liste).

#include <stdio.h>

2 #include <stdlib.h>

#include "queue.h"

4 #define pulisci system("cls")

#define pausa while(getchar ()!=’\n’); getchar ()

6 void print_adt_stream(Queue *coda , FILE *stream);

int menu();

8 int read_adt_stream(Queue *coda , FILE *stream);

int main()

103

Page 112: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

10

Queue *coda=NULL;

12 Item *item;

int choose;

14 int fine =0;

int errori;

16 char path[MAX_PATH ]=0;

FILE *f;

18 while (!fine)

20 errori =0;

choose=menu();

22 switch(choose)

24 case 1:

delete_queue(coda);

26 if((coda = new_queue ())==NULL)

errori += printf("Errore nell’allocazione della

memoria .\n");

28 break;

case 2:

30 if((item=i_read_by_stream(stdin))==NULL)

errori += printf("Errore nell’allocazione della

memoria .\n");

32 if(! enqueue(coda , item))

errori += printf("Errore nell’inserimento dell’item.\n

");

34 break;

case 3:

36 if((item = dequeue(coda))==NULL)

errori += printf("Errore nell’estrazione dell’item.\n"

);

38 else

40 errori =1;

printf("Valore estratto: ");

42 i_print(item , stdout);

printf("\n");

44 i_free(item);

46 break;

case 4:

48 errori =1;

print_adt_stream(coda , stdout);

50 break;

case 5:

52 printf("Introduci il percorso nel quale salvare la

struttura dati:\t");

scanf("%s", path);

54 if((f=fopen(path , "w"))!=NULL)

56 print_adt_stream(coda , f);

fflush(f);

58 fclose(f);

60 break;

case 6:

62 printf("Introduci il percorso dal quale leggere la

struttura dati:\t");

scanf("%s", path);

64 if((f=fopen(path , "r"))!=NULL)

104

Page 113: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

66 if(is_empty_queue(coda))

68 delete_queue(coda);

if((coda = new_queue ())==NULL)

70 printf("Errore nell’allocazione della

memoria .\n");

72 if(! read_adt_stream(coda , f))

74 errori = 1;

printf("Errore nella lettura dell’ADT dal file\n

");

76

fclose(f);

78

break;

80 case 7:

delete_queue(coda);

82 fine =1;

84 if(errori)

pausa;

86

return 0;

88

int read_adt_stream(Queue *coda , FILE *stream)

90

Item *item;

92 while(fgetc(stream)!=’\n’)

;

94 while ((item=i_read_by_stream(stream))!=NULL)

if(! enqueue(coda , item))

96 return 0;

return 1;

98

void print_adt_stream(Queue *coda , FILE *stream)

100

Item *item;

102 if(is_empty_queue(coda))

fprintf(stream , "Struttura vuota.\n");

104 else

106 fprintf(stream , "Valori estratti :\n");

while((item = dequeue(coda))!=NULL)

108

fprintf(stream , "\t");

110 i_print(item , stream);

fprintf(stream , "\n");

112 i_free(item);

114

116 int menu()

118 int choose;

pulisci;

120 do

122 printf("\nSeleziona l’operazione desiderata :\n\t1 - Creazione

nuova Queue\n\t2 - Inserimento di un nuovo elemento\n\t3 -

Estrazione e stampa di un elemento\n\t4 - Visualizzazione a

video di tutti gli elementi\n\t5 - Salvataggio su file di

105

Page 114: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

tutti gli elementi\n\t6 - Caricamento degli elementi da file\

n\t7 - Esci\nIntroduci la scelta desiderata :\t");

scanf("%d", &choose);

124 if(choose <1 || choose >7)

126 pulisci;

printf("\tERRORE IMMISSIONE DATI!");

128

130 while(choose <1 || choose >7);

return choose;

132 Listing 10.1: Queue (client.c)

1 #include <stdio.h>

#include <malloc.h>

3 typedef int Item;

void i_print(Item *item , FILE *stream);

5 void i_free(Item *item);

Item *i_read_by_stream(FILE *stream); Listing 10.2: Queue (item.h)

1 #include "item.h"

void i_print(Item *item , FILE *stream)

3

fprintf(stream , "%d", *item);

5

void i_free(Item *item)

7

if(item==NULL)

9 return;

free(item);

11

Item *i_read_by_stream(FILE *stream)

13

Item *res;

15 if((res=(Item *) malloc(sizeof(Item)))==NULL || stream ==NULL)

return NULL;

17 if(stream == stdin)

printf("Introduci un numero intero :\t");

19 if(fscanf(stream , "%d", res)!=1)

21 free(res);

return NULL;

23

return res;

25 Listing 10.3: Queue (item.c)

Per la versione con allocazione dinamica saranno necessari questi altri due listati1 #include <stdio.h>

#include <malloc.h>

3 #include "item.h"

struct queue_item_t

5

Item *item;

7 struct queue_item_t *next;

;

9 typedef struct Queue_t

106

Page 115: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

11 struct queue_item_t *head , *tail;

Queue;

13 Queue *new_queue ();

int is_empty_queue(Queue *queue);

15 int enqueue(Queue *queue , Item *add);

Item *dequeue(Queue *queue);

17 void print_dequeue(Queue *queue , FILE *stream);

void clean_queue(Queue *queue);

19 void delete_queue(Queue *queue); Listing 10.4: Queue (queue.h)

#include <stdio.h>

2 #include "queue.h"

Queue *new_queue ()

4

Queue *res;

6 if((res= (Queue *) malloc(sizeof(Queue)))==NULL)

return NULL;

8 res ->head = NULL;

res ->tail = NULL;

10 return res;

12 int is_empty_queue(Queue *queue)

14 return queue==NULL || (queue ->tail==NULL && queue ->head==NULL);

16 int enqueue(Queue *queue , Item *add)

18 if(queue ==NULL)

return 0;

20 struct queue_item_t *to_add;

if(( to_add =( struct queue_item_t *) malloc(sizeof(struct queue_item_t)

))==NULL)

22 return 0;

to_add ->item = add;

24 to_add ->next = NULL;

if(queue ->tail!=NULL)

26 queue ->tail ->next = to_add;

queue ->tail = to_add;

28 if(queue ->head==NULL)

queue ->head = to_add;

30 printf("enqueue (..., ");

i_print(add , stdout);

32 printf(")\n");

return 1;

34

Item *dequeue(Queue *queue)

36

if(is_empty_queue(queue))

38 return NULL;

struct queue_item_t *head;

40 Item *item;

head = queue ->head;

42 queue ->head = queue ->head ->next;

if(queue ->head==NULL)

44 queue ->tail=NULL;

item = head ->item;

46 free(head);

return item;

48

107

Page 116: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

void print_dequeue(Queue *queue , FILE *stream)

50

Item *extract;

52 extract = dequeue(queue);

if(extract ==NULL)

54 fprintf(stream , "ERRORE DI ESTRAZIONE\n");

else

56

i_print(extract , stream);

58 fprintf(stream , "\n");

i_free(extract);

60

62 void clean_queue(Queue *queue)

64 if(queue==NULL)

return;

66 Item *extracted;

while (( extracted=dequeue(queue))!=NULL)

68 i_free(extracted);

70 void delete_queue(Queue *queue)

72 if(queue==NULL)

return;

74 clean_queue(queue);

free(queue);

76 Listing 10.5: Queue (queue.c)

mentre per la versione statico sono necessari questi file1 #include <stdio.h>

#include <malloc.h>

3 #include "item.h"

#define lenght_max_queue 10

5 typedef struct Queue_t

7 Item *item[lenght_max_queue ];

int head , tail;

9 Queue;

Queue *new_queue ();

11 int is_empty_queue(Queue *queue);

int is_full_queue(Queue *queue);

13 int enqueue(Queue *queue , Item *add);

Item *dequeue(Queue *queue);

15 void print_dequeue(Queue *queue , FILE *stream);

void clean_queue(Queue *queue);

17 void delete_queue(Queue *queue); Listing 10.6: Queue (queue.h)

1 #include "queue.h"

Queue *new_queue ()

3

Queue *res;

5 if((res=( Queue *) malloc(sizeof(Queue)))==NULL)

return NULL;

7 res ->head=res ->tail =0;

return res;

9

int is_empty_queue(Queue *queue)

108

Page 117: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

11

return queue!=NULL && queue ->tail==queue ->head;

13

int is_full_queue(Queue *queue)

15

return (queue ->tail)+1== queue ->head;

17

int enqueue(Queue *queue , Item *add)

19

if(queue ==NULL)

21 return 0;

if(is_full_queue(queue))

23 return 0;

queue ->item[queue ->tail] = add;

25 queue ->tail = (queue ->tail +1)%lenght_max_queue;

return 1;

27

Item *dequeue(Queue *queue)

29

if(is_empty_queue(queue))

31 return NULL;

Item *item;

33 item = queue ->item[queue ->head];

queue ->head = (queue ->head +1)%lenght_max_queue;

35 return item;

37 void print_dequeue(Queue *queue , FILE *stream)

39 Item *extract;

extract = dequeue(queue);

41 if(extract ==NULL)

fprintf(stream , "ERRORE DI ESTRAZIONE\n");

43 else

45 i_print(extract , stream);

fprintf(stream , "\n");

47 i_free(extract);

49

void clean_queue(Queue *queue)

51

if(queue ==NULL)

53 return;

Item *extracted;

55 while (( extracted=dequeue(queue))!=NULL)

i_free(extracted);

57

void delete_queue(Queue *queue)

59

if(queue ==NULL)

61 return;

clean_queue(queue);

63 free(queue);

Listing 10.7: Queue (queue.c)

10.2 Esercizio n. 2: gestione di strutture LIFO.

Si realizzi un programma C che, attraverso un’apposita interfaccia utente, permetta di gestire una strut-tura dati di tipo LIFO (pila).

109

Page 118: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Le operazione permesse devono essere quelle di:

• creazione di una nuova struttura (vuota).

• inserimento di un nuovo elemento della struttura.

• estrazione di un elemento dalla struttura.

• visualizzazione (a video) di tutti gli elementi nella base dati (opzionale).

• salvataggio della base dati su file (opzionale).

• caricamento di una nuova base dati da file (opzionale).

In questo esercizio, il programma deve essere realizzato su tre moduli distinti:

• l’interfaccia utente (il client).

• un modulo con le funzioni per la gestione della coda.

• un modulo con le funzioni per la gestione dei singoli dati.

In particolare, si desidera che l’implementazione della libreria sulla struttura dati corrisponda a un ADTdi I categoria.Si supponga che ogni elemento della base dati possa essere (a scelta del programmatore):

• una stringa di lunghezza massima pari a 50 caratteri.

• un numero intero.

• una struttura composta da due campi (stringa + numero).

Si realizzi il programma in due versioni:

• supponendo che il numero massimo di elementi nella coda sia pari a 100 (implementazione tramitevettori).

• supponendo che non ci sia limite al numero di elementi che e possibile memorizzare nella coda(implementazione tramite liste).

#include <stdio.h>

2 #include <stdlib.h>

#include "stack.h"

4 #define pulisci system("cls")

#define pausa while(getchar ()!=’\n’); getchar ()

6 void print_adt_stream(Stack *pila , FILE *stream);

int menu();

8 int read_adt_stream(Stack *pila , FILE *stream);

int main()

10

Stack *pila=NULL;

12 Item *item;

int choose;

14 int fine =0;

int errori;

16 char path[MAX_PATH ]=0;

FILE *f;

18 while (!fine)

20 errori =0;

choose=menu();

22 switch(choose)

24 case 1:

delete_stack(pila);

26 if((pila = new_stack ())==NULL)

errori += printf("Errore nell’allocazione della

memoria .\n");

110

Page 119: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

28 break;

case 2:

30 if((item=i_read_by_stream(stdin))==NULL)

errori += printf("Errore nell’allocazione della

memoria .\n");

32 if(!push(pila , item))

errori += printf("Errore nell’inserimento dell’item.\n

");

34 break;

case 3:

36 if((item = pop(pila))==NULL)

errori += printf("Errore nell’estrazione dell’item.\n"

);

38 else

40 errori =1;

printf("Valore estratto: ");

42 i_print(item , stdout);

printf("\n");

44 i_free(item);

46 break;

case 4:

48 errori =1;

print_adt_stream(pila , stdout);

50 break;

case 5:

52 printf("Introduci il percorso nel quale salvare la

struttura dati:\t");

scanf("%s", path);

54 if((f=fopen(path , "w"))!=NULL)

56 print_adt_stream(pila , f);

fflush(f);

58 fclose(f);

60 break;

case 6:

62 printf("Introduci il percorso dal quale leggere la

struttura dati:\t");

scanf("%s", path);

64 if((f=fopen(path , "r"))!=NULL)

66 if(is_empty_stack(pila))

68 delete_stack(pila);

if((pila = new_stack ())==NULL)

70 printf("Errore nell’allocazione della

memoria .\n");

72 if(! read_adt_stream(pila , f))

74 errori = 1;

printf("Errore nella lettura dell’ADT dal file\n

");

76

fclose(f);

78

break;

80 case 7:

delete_stack(pila);

82 fine =1;

111

Page 120: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

84 if(errori)

pausa;

86

return 0;

88

int read_adt_stream(Stack *pila , FILE *stream)

90

Item *item;

92 while(fgetc(stream)!=’\n’)

;

94 while ((item=i_read_by_stream(stream))!=NULL)

if(!push(pila , item))

96 return 0;

return 1;

98

void print_adt_stream(Stack *pila , FILE *stream)

100

Item *item;

102 if(is_empty_stack(pila))

fprintf(stream , "Struttura vuota.\n");

104 else

106 fprintf(stream , "Valori estratti :\n");

while ((item = pop(pila))!=NULL)

108

fprintf(stream , "\t");

110 i_print(item , stream);

fprintf(stream , "\n");

112 i_free(item);

114

116 int menu()

118 int choose;

pulisci;

120 do

122 printf("\nSeleziona l’operazione desiderata :\n\t1 - Creazione

nuovo Stack\n\t2 - Inserimento di un nuovo elemento\n\t3 -

Estrazione e stampa di un elemento\n\t4 - Visualizzazione a

video di tutti gli elementi\n\t5 - Salvataggio su file di

tutti gli elementi\n\t6 - Caricamento degli elementi da file\

n\t7 - Esci\nIntroduci la scelta desiderata :\t");

scanf("%d", &choose);

124 if(choose <1 || choose >7)

126 pulisci;

printf("\tERRORE IMMISSIONE DATI!");

128

130 while(choose <1 || choose >7);

return choose;

132 Listing 10.8: Stack (client.c)

1 #include <stdio.h>

#include <malloc.h>

3 typedef int Item;

void i_print(Item *item , FILE *stream);

112

Page 121: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

5 void i_free(Item *item);

Item *i_read_by_stream(FILE *stream); Listing 10.9: Stack (item.h)

1 #include "item.h"

void i_print(Item *item , FILE *stream)

3

fprintf(stream , "%d", *item);

5

void i_free(Item *item)

7

if(item==NULL)

9 return;

free(item);

11

Item *i_read_by_stream(FILE *stream)

13

Item *res;

15 if((res=(Item *) malloc(sizeof(Item)))==NULL || stream ==NULL)

return NULL;

17 if(stream ==stdin)

printf("Introduci un numero intero :\t");

19 if(fscanf(stream , "%d", res)!=1)

21 free(res);

return NULL;

23

return res;

25 Listing 10.10: Stack (item.c)

Per la versione con allocazione dinamica saranno necessari questi altri due listati1 #include <stdio.h>

#include <malloc.h>

3 #include "item.h"

struct stack_item_t

5

Item *item;

7 struct stack_item_t *next;

;

9 typedef struct Stack_t

11 struct stack_item_t *head;

Stack;

13 Stack *new_stack ();

int is_empty_stack(Stack *queue);

15 int push(Stack *pila , Item *add);

Item *pop(Stack *pila);

17 void print_dequeue(Stack *pila , FILE *stream);

void clean_stack(Stack *pila);

19 void delete_stack(Stack *pila); Listing 10.11: Stack (stack.h)

1 #include <stdio.h>

#include "stack.h"

3 Stack *new_stack ()

5 Stack *res;

if((res= (Stack *) malloc(sizeof(Stack)))==NULL)

113

Page 122: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

7 return NULL;

res ->head = NULL;

9 return res;

11 int is_empty_stack(Stack *queue)

13 return queue==NULL || queue ->head==NULL;

15 int push(Stack *pila , Item *add)

17 if(pila==NULL)

return 0;

19 struct stack_item_t *to_add;

if(( to_add =( struct stack_item_t *) malloc(sizeof(struct stack_item_t)

))==NULL)

21 return 0;

to_add ->item = add;

23 to_add ->next = pila ->head;

pila ->head = to_add;

25 return 1;

27 Item *pop(Stack *pila)

29 if(is_empty_stack(pila))

return NULL;

31 struct stack_item_t *head;

Item *item;

33 head = pila ->head;

pila ->head = pila ->head ->next;

35 item = head ->item;

free(head);

37 return item;

39 void print_pop(Stack *pila , FILE *stream)

41 Item *extract;

extract = pop(pila);

43 if(extract ==NULL)

fprintf(stream , "ERRORE DI ESTRAZIONE\n");

45 else

47 i_print(extract , stream);

fprintf(stream , "\n");

49 i_free(extract);

51

void clean_stack(Stack *pila)

53

if(pila==NULL)

55 return;

Item *extracted;

57 while (( extracted=pop(pila))!=NULL)

i_free(extracted);

59

void delete_stack(Stack *pila)

61

if(pila==NULL)

63 return;

clean_stack(pila);

65 free(pila);

114

Page 123: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Listing 10.12: Stack (stack.c)

mentre per la versione statico sono necessari questi file1 #include <stdio.h>

#include <malloc.h>

3 #include "item.h"

#define lenght_max_stack 10

5 typedef struct Stack_t

7 Item *item[lenght_max_stack ];

int head;

9 Stack;

Stack *new_stack ();

11 int is_empty_stack(Stack *queue);

int push(Stack *pila , Item *add);

13 Item *pop(Stack *pila);

void print_dequeue(Stack *pila , FILE *stream);

15 void clean_stack(Stack *pila);

void delete_stack(Stack *pila); Listing 10.13: Stack (stack.h)

1 #include <stdio.h>

#include "stack.h"

3 Stack *new_stack ()

5 Stack *res;

if((res= (Stack *) malloc(sizeof(Stack)))==NULL)

7 return NULL;

res ->head = 0;

9 return res;

11 int is_full_stack(Stack *pila)

13 return pila==NULL || pila ->head >= lenght_max_stack;

15 int is_empty_stack(Stack *pila)

17 return pila==NULL || pila ->head ==0;

19 int push(Stack *pila , Item *add)

21 if(pila==NULL)

return 0;

23 pila ->item[pila ->head ++] = add;

return 1;

25

Item *pop(Stack *pila)

27

if(is_empty_stack(pila))

29 return NULL;

Item *item;

31 item = pila ->item[--pila ->head];

return item;

33

void print_pop(Stack *pila , FILE *stream)

35

Item *extract;

37 extract = pop(pila);

if(extract ==NULL)

115

Page 124: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

39 fprintf(stream , "ERRORE DI ESTRAZIONE\n");

else

41

i_print(extract , stream);

43 fprintf(stream , "\n");

i_free(extract);

45

47 void clean_stack(Stack *pila)

49 if(pila==NULL)

return;

51 Item *extracted;

while (( extracted=pop(pila))!=NULL)

53 i_free(extracted);

55 void delete_stack(Stack *pila)

57 if(pila==NULL)

return;

59 clean_stack(pila);

free(pila);

61 Listing 10.14: Stack (stack.c)

116

Page 125: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Capitolo 11

Esercitazione 8

11.1 Esercizio n. 1: gestione di una coda prioritaria - I

In un centro sviluppo di una grande azienda di elettronica si fa uso di un insieme consistente di pc,interconnessi tra loro, per eseguire numerose simulazioni sui progetti sviluppati dagli ingegneri lı impiegati.Piu precisamente, quando un progettista vuole compiere un determinato test, lancia un comando (job) cheviene “raccolto” dal sistema di gestione comune e poi eseguito su uno qualunque dei calcolatori dedicati.La strategia seguita dal gestore e la seguente:

• Se, nel momento in cui viene lanciato un job, e presente almeno un computer libero, il job vieneimmediatamente eseguito su di esso.

• Se non e disponibile alcun calcolatore per eseguire un job, il job stesso viene temporaneamente“salvato” in una lista d’attesa.

• Nel momento in cui un job termina la sua esecuzione su un pc, il gestore viene “avvertito” e unaltro job (se presente nella lista d’attesa) viene selezionato e lanciato su di esso. La selezione delnuovo job da eseguire avviene secondo un criterio di massima priorita.

Si desidera implementare un semplice programma che emuli il comportamento del gestore dei job.In particolare, il sistema deve essere realizzato su tre moduli:

• un modulo per la gestione dei singoli job: ciascun job e in realta caratterizzato da numerose infor-mazioni, ma per semplicita si supponga che, oltre al livello di priorita (intero positivo), ad esso siaassociata solo una stringa univoca di lunghezza massima pari a 30 caratteri.

• un modulo per la gestione della lista d’attesa: tale struttura dati, di fatto corrispondente a unacoda prioritaria, sia implementata (come quasi ADT o ADT di I categoria) mediante:

– una lista ordinata.

– un heap, nell’ipotesi in cui il numero di job che possono essere memorizzati nella coda sia alpiu pari a 100.

• un programma principale (client) che si occupa dell’interfaccia del gestore verso il mondo esterno,al cui interno sono realizzate le due funzioni con cui il gestore puo essere richiamato (ovvero, larichiesta di esecuzione di un nuovo job da parte di un progettista e la segnalazione di terminazionedi un job che occupava uno dei computer). Per semplicita, si includa in tale modulo anche un mainche richiami tali funzioni a scelta dell’utente, richiedendo all’utente stesso le altre informazioni chesono necessarie per attivare la funzione desiderata (per esempio, se si richiede di eseguire un nuovojob, il suo “nome” e la sua priorita).

Il programma, infine, visualizzi sul video opportune informazioni a fronte di ogni richiesta ricevuta (peresempio, che la richiesta di esecuzione un nuovo job e stata acquisita ma il job e stato salvato nella listad’attesa, oppure che un determinato job e stato estratto dalla lista d’attesa e lanciato su un calcolatoreche si e reso disponibile, etc.).Il numero totale di computer dedicati che sono disponibili sia una costante predefinita, dichiarata nelmodulo principale.

1 #include <stdio.h>

#include <string.h>

117

Page 126: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

3 #include "PriorityQueue.h"

#define n_computer 3

5 #define max_command_lenght 256

#define log_file "log.txt"

7 int main()

9 char cmd[max_command_lenght +1], name [30+1];

int fine=0, i;

11 FILE *flog;

job *computer[n_computer ]=0 , *tmp;

13 Priority_Queue *job_list;

if(( job_list=q_init ())==NULL)

15 return 1;

if((flog=fopen(log_file , "w"))==NULL)

17 return 2;

while (!fine)

19

printf(">> ");

21 fgets(cmd , max_command_lenght , stdin);

if(strstr(cmd , "exit")==cmd)

23 fine =1;

else if(strstr(cmd , "job")==cmd)

25

if((tmp = j_read_by_string(cmd +4))==NULL)

27 printf(" Errore lettura job.");

else if(! q_enqueue(job_list , tmp))

29 printf(" Errore inserimento job.");

else

31

printf(" Job %s (p=%d) acquisito. ", j_getName(tmp),

j_getPriority(tmp));

33 fprintf(flog , "Job %s (p=%d) acquisito. ", j_getName(tmp

), j_getPriority(tmp));

for(i=0; i<n_computer && computer[i]!= NULL; i++)

35 ;

if(i!= n_computer)

37

printf("Job lanciato su pc %d. ", i);

39 fprintf(flog , "Job lanciato su pc %d. ", i);

computer[i] = q_dequeue(job_list);

41

else

43

printf("Job messo in attesa. ");

45 fprintf(flog , "Job messo in attesa. ");

47

printf("\n");

49 fprintf(flog , "\n");

51 else if(strstr(cmd , "stop")==cmd)

53 sscanf(cmd+4, "%s", name);

for(i=0; i<n_computer ; i++)

55 if(computer[i]!= NULL && strcmp(name , j_getName(computer[

i]))==0)

break;

57 if(i== n_computer)

printf(" Processo non trovato in esecuzione. ");

59 else

118

Page 127: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

61 printf(" Job %s (p=%d) terminato. ", j_getName(

computer[i]), j_getPriority(computer[i]));

fprintf(flog , "Job %s (p=%d) terminato. ", j_getName(

computer[i]), j_getPriority(computer[i]));

63 j_free(computer[i]);

computer[i] = q_dequeue(job_list);

65 if(computer[i]!= NULL)

67 printf("Job %s (p=%d) lanciato su pc %d. ",

j_getName(computer[i]), j_getPriority(computer[i

]), i);

fprintf(flog , "Job %s (p=%d) lanciato su pc %d. ",

j_getName(computer[i]), j_getPriority(computer[i

]), i);

69

71 printf("\n");

fprintf(flog , "\n");

73

else

75 printf(" Comando non riconosciuto. (job , stop , exit)\n");

77 fflush(flog);

fclose(flog);

79 q_free(job_list);

return 0;

81 Listing 11.1: Coda prioritaria - I (client.c)

1 #include <stdio.h>

#include <malloc.h>

3 #include <string.h>

typedef unsigned int Priority;

5 typedef struct

7 Priority priority;

char *name;

9 job;

job *j_init(Priority priority , char *name);

11 void j_print(job *JOB , FILE *stream);

void j_free(job *JOB);

13 job *j_read_by_stream(FILE *stream);

job *j_read_by_string(char *string);

15 char *j_getName(job *JOB);

int j_getPriority(job *JOB); Listing 11.2: Coda prioritaria - I (job.h)

1 #include "job.h"

#define max_name_lenght 30

3 job *j_init(Priority priority , char *name)

5 job *res;

if(priority <=0 || name==NULL)

7 return NULL;

if((res=(job *) malloc(sizeof(job)))==NULL)

9 return NULL;

if((res ->name=strdup(name))==NULL)

11

free(res);

13 return NULL;

119

Page 128: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

15 res ->priority = priority;

return res;

17

void j_print(job *JOB , FILE *stream)

19

if(JOB==NULL || stream ==NULL)

21 return;

fprintf(stream , "%s (%d)\n", JOB ->name , JOB ->priority);

23

void j_free(job *JOB)

25

if(JOB==NULL)

27 return;

if(JOB ->name==NULL)

29 free(JOB ->name);

free(JOB);

31

job *j_read_by_stream(FILE *stream)

33

if(stream ==NULL)

35 return NULL;

char name_tmp[max_name_lenght +1];

37 Priority priority_tmp;

if(stream == stdin)

39 printf("Introduci: nome priorita ’\n");

if(fscanf(stream , "%s %d", name_tmp , &priority_tmp)==2)

41 return j_init(priority_tmp , name_tmp);

else

43 return NULL;

45 job *j_read_by_string(char *string)

47 if(string ==NULL)

return NULL;

49 char name_tmp[max_name_lenght +1];

Priority priority_tmp;

51 if(sscanf(string , "%s %d", name_tmp , &priority_tmp)==2)

return j_init(priority_tmp , name_tmp);

53 else

return NULL;

55

char *j_getName(job *JOB)

57

if(JOB==NULL)

59 return NULL;

return JOB ->name;

61

int j_getPriority(job *JOB)

63

if(JOB==NULL)

65 return -1;

return JOB ->priority;

67 Listing 11.3: Coda prioritaria - I (job.c)

#include "job.h"

2 typedef job ITEM;

int i_compare(ITEM *I1 , ITEM *I2);

4 char *i_getDescription(ITEM *I);

void i_free(ITEM *I);

120

Page 129: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

Listing 11.4: Coda prioritaria - I (ITEM.h)

1 #include "ITEM.h"

int i_compare(ITEM *I1 , ITEM *I2)

3

if(I1==NULL || I2==NULL)

5 return 0;

return I1 ->priority -I2 ->priority;

7

char *i_getDescription(ITEM *I)

9

return j_getName(I);

11

void i_free(ITEM *I)

13

j_free(I);

15 Listing 11.5: Coda prioritaria - I (ITEM.c)

Per la versione con heap saranno necessari questi altri due listati#include <stdio.h>

2 #include <malloc.h>

#include "ITEM.h"

4 #define max_heap_dim 127

#define LEFT(i) 2*i+1

6 #define RIGHT(i) 2*i+2

#define PARENT(i) (int)(i-1)/2

8 typedef struct

10 ITEM ** value;

int heapsize , max_heapsize;

12 heap;

heap *h_init(int size);

14 int h_insert(heap *HEAP , ITEM *V);

void h_heapify(heap *HEAP , int root);

16 ITEM *h_remove(heap *HEAP);

void h_free(heap *HEAP); Listing 11.6: Coda prioritaria - I (HEAP.h)

1 #include "HEAP.h"

heap *h_init(int size)

3

if(size <=0)

5 return NULL;

heap *res;

7 if((res=(heap *) malloc(sizeof(heap)))==NULL)

return NULL;

9 int i;

i=1;

11 while(i<=size && i<max_heap_dim)

i<<=1;

13 i--;

if((res ->value =(ITEM **) malloc(i*sizeof(ITEM *)))==NULL)

15

free(res);

17 return NULL;

19 res ->heapsize =0;

121

Page 130: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

res ->max_heapsize=i;

21 return res;

23 int h_insert(heap *HEAP , ITEM *V)

25 if(HEAP==NULL || V==NULL || HEAP ->heapsize >=HEAP ->max_heapsize)

return 0;

27 int position = HEAP ->heapsize;

while(position !=0 && i_compare(V, HEAP ->value[PARENT(position)]) >0)

29

HEAP ->value[position] = HEAP ->value[PARENT(position)];

31 position = PARENT(position);

33 HEAP ->value[position] = V;

HEAP ->heapsize ++;

35 return 1;

37 void h_print(heap *HEAP)

39 if(HEAP==NULL)

return ;

41 int i;

int l=1;

43 for(i=0; i<HEAP ->heapsize; i++)

45 printf("%s", i_getDescription(HEAP ->value[i]));

if(i==(1<<l) -2)

47

printf("\n");

49 l++;

51

printf("\n");

53

void h_heapify(heap *HEAP , int root)

55

ITEM *t;

57 if(HEAP==NULL)

return;

59 int largest = root;

if(LEFT(root)<HEAP ->heapsize && i_compare(HEAP ->value[LEFT(root)],

HEAP ->value[root]) >0)

61 largest = LEFT(root);

if(RIGHT(root)<HEAP ->heapsize && i_compare(HEAP ->value[RIGHT(root)],

HEAP ->value[largest ]) >0)

63 largest = RIGHT(root);

if(largest !=root)

65

t = HEAP ->value[root];

67 HEAP ->value[root] = HEAP ->value[largest ];

HEAP ->value[largest] = t;

69 h_heapify(HEAP , largest);

71

ITEM *h_remove(heap *HEAP)

73

if(HEAP==NULL || HEAP ->heapsize ==0)

75 return NULL;

ITEM *VAL = HEAP ->value [0];

77 HEAP ->value [0] = HEAP ->value[--HEAP ->heapsize ];

HEAP ->value[HEAP ->heapsize] = NULL;

79 h_heapify(HEAP , 0);

122

Page 131: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

return VAL;

81

void h_free(heap *HEAP)

83

if(HEAP==NULL)

85 return;

int i;

87 for(i=0; i<HEAP ->heapsize; i++)

i_free(HEAP ->value[i]);

89 free(HEAP ->value);

free(HEAP);

91 Listing 11.7: Coda prioritaria - I (HEAP.c)

#include "HEAP.h"

2 typedef heap Priority_Queue;

Priority_Queue *q_init ();

4 int q_enqueue(Priority_Queue *Queue , ITEM *I);

ITEM *q_dequeue(Priority_Queue *Queue);

6 int q_is_empty(Priority_Queue *Queue);

void q_free(Priority_Queue *Queue); Listing 11.8: Coda prioritaria - I (PriorityQueue.h)

1 #include "Priority_queue.h"

Priority_Queue *q_init ()

3

Priority_Queue *res;

5 if((res=h_init(max_heap_dim))==NULL)

return NULL;

7 return res;

9 int q_enqueue(Priority_Queue *Queue , ITEM *I)

11 if(Queue ==NULL || I==NULL)

return 0;

13 return h_insert(Queue , I);

15 ITEM *q_dequeue(Priority_Queue *Queue)

17 return h_remove(Queue);

19 int q_is_empty(Priority_Queue *Queue)

21 if(Queue ==NULL)

return 1;

23 return Queue ->heapsize ==0;

25 void q_free(Priority_Queue *Queue)

27 h_free(Queue);

Listing 11.9: Coda prioritaria - I (PriorityQueue.c)

mentre per la versione con linked-list ordinata sono necessari questi file1 #include <malloc.h>

#include "ITEM.h"

3 struct node

5 ITEM *item;

123

Page 132: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

struct node *next;

7 ;

typedef struct

9

struct node *head;

11 LIST;

LIST *l_init ();

13 void l_free(LIST *List);

int l_add(LIST *List , ITEM *I);

15 ITEM *l_extract_max(LIST *List);

int l_is_empty(LIST *List);

17 void l_print(LIST *List , FILE *stream); Listing 11.10: Coda prioritaria - I (LIST.h)

1 #include "LIST.h"

LIST *l_init ()

3

LIST *res;

5 if((res=(LIST *) malloc(sizeof(LIST)))==NULL)

return NULL;

7 res ->head=NULL;

return res;

9

void l_free(LIST *List)

11

if(List==NULL)

13 return;

struct node *NODE , *extract;

15 NODE = List ->head;

while(NODE!=NULL)

17

extract = NODE;

19 NODE = NODE ->next;

free(extract);

21

free(List);

23

int l_add(LIST *List , ITEM *I)

25

struct node *to_add , *succ , *pred;

27 if(List==NULL)

return 0;

29 if(( to_add =( struct node *) malloc(sizeof(struct node)))==NULL)

return 0;

31 to_add ->item = I;

to_add ->next = NULL;

33 succ = List ->head;

pred = NULL;

35 while(succ!=NULL)

37 if(i_compare(succ ->item , I) <0)

break;

39 pred = succ;

succ = succ ->next;

41

if(succ!=NULL)

43

if(pred==NULL)

45

to_add ->next = List ->head;

47 List ->head = to_add;

124

Page 133: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

49 else

51 to_add ->next = succ;

pred ->next = to_add;

53

55 else

57 if(pred==NULL)

List ->head = to_add;

59 else

pred ->next = to_add;

61

return 1;

63

ITEM *l_extract_max(LIST *List)

65

if(List==NULL || List ->head==NULL)

67 return NULL;

struct node *extract;

69 ITEM *res;

extract = List ->head;

71 List ->head = List ->head ->next;

res = extract ->item;

73 free(extract);

return res;

75

int l_is_empty(LIST *List)

77

if(List==NULL)

79 return 1;

return List ->head==NULL;

81

void l_print(LIST *List , FILE *stream)

83

if(List==NULL || stream ==NULL)

85 return;

struct node *root;

87 root = List ->head;

while(root!=NULL)

89

i_print(root ->item , stream);

91 root = root ->next;

93 Listing 11.11: Coda prioritaria - I (LIST.c)

1 #include "LIST.h"

typedef LIST Priority_Queue;

3 Priority_Queue *q_init ();

int q_enqueue(Priority_Queue *Queue , ITEM *I);

5 ITEM *q_dequeue(Priority_Queue *Queue);

int q_is_empty(Priority_Queue *Queue);

7 void q_free(Priority_Queue *Queue); Listing 11.12: Coda prioritaria - I (PriorityQueue.h)

1 #include "Priority_queue.h"

Priority_Queue *q_init ()

3

125

Page 134: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

return l_init ();

5

int q_enqueue(Priority_Queue *Queue , ITEM *I)

7

if(Queue==NULL || I==NULL)

9 return 0;

return l_add(Queue , I);

11

ITEM *q_dequeue(Priority_Queue *Queue)

13

return l_extract_max(Queue);

15

int q_is_empty(Priority_Queue *Queue)

17

return l_is_empty(Queue);

19

void q_free(Priority_Queue *Queue)

21

l_free(Queue);

23 Listing 11.13: Coda prioritaria - I (PriorityQueue.c)

11.2 Esercizio n. 2: gestione di una coda prioritaria - II

Si modifichi il codice sviluppato nell’esercizio precedente in modo tale che:

• ogni job sia caratterizzato, oltre che dal nome e dalla priorita, anche da un tempo di arrivo (ovvero,l’orario in cui ne e stata richiesta l’esecuzione) e da una durata. Entrambi siano espressi nel formatohh:mm:ss.

• l’insieme di tutti i job da eseguire, in numero ignoto, sia memorizzato in un file di testo, in ragionedi un job per riga del file, con il formato seguente:

<nome> <priorita> <arrivo> <durata>

Si assuma che i job contenuti in tale file siano ordinati per tempi di arrivo crescenti.

• l’operazione che il gestore dei job deve eseguire non sia di volta in volta richiesta all’utente: piuttosto,a partire dal contenuto del file suddetto, il client dell’applicazione deduca automaticamente quandoi computer sono disponibili e l’istante di tempo in cui ogni job viene effettivamente lanciato su unodei calcolatori.

• il programma visualizzi sul video un insieme opportuno di informazioni su ciascun avvenimento inordine cronologico.

Suggerimento: Il client dell’applicazione, a partire dal contenuto del file dei job, simuli il comporta-mento del gestore seguendo un ordine cronologico: ogni qual volta un nuovo job viene lanciato su uncomputer, infatti, l’applicazione conosce il momento in cui il calcolatore sara di nuovo disponibile. Inogni istante, pertanto il gestore sa quanti sono i calcolatori liberi e quando ogni job che e stato lancia-to sara terminato. Processando un job per volta dal file di ingresso, quindi, e possibile capire qual el’avvenimento che accade per primo tra la presa in carico del nuovo job e un mutamento nello stato deicalcolatori e/o dei job in lista d’attesa . . . .La variazione rispetto all’esercizio 1 consiste solo nel client e nei campi della struttura job; la gestionedella coda prioritaria resta invariata.#include <stdio.h>

2 #include <stdlib.h>

#include "Priority_queue.h"

4 #define jobList "joblist.txt"

#define n_computer 3

6 #define log_file "log.txt"

126

Page 135: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

int execute_job(job *computer[], HOUR *hour_to_terminate [], int *

pc_usati , int *cpu_to_terminate , job *to_add , HOUR *actual_moment);

8 HOUR *terminate_job(job *computer[], HOUR *hour_to_terminate [], int *

pc_usati , int *cpu_to_terminate);

int main()

10

job *tmp , *tmp_extract , *computer[n_computer ]=0;

12 FILE *fin , *flog;

Priority_Queue *job_list;

14 HOUR *hour_to_terminate[n_computer ]=0, *h_tmp=NULL;

int cpu_to_terminate =-1, pc_usati =0;

16 if((fin=fopen(jobList , "r"))==NULL || (flog=fopen(log_file , "w"))==

NULL)

return 1;

18 if(( job_list=q_init ())==NULL)

return 2;

20 while ((tmp = j_read_by_stream(fin))!=NULL)

22 if(! q_enqueue(job_list , tmp))

24 printf("ERRORE inserimento job.\n");

continue;

26

if(pc_usati !=0)

28

while(H_compare(tmp ->request , hour_to_terminate[

cpu_to_terminate ]) >0)

30

H_print(hour_to_terminate[cpu_to_terminate], stdout);

32 printf(" > Job %s (p=%d) terminato. ", j_getName(

computer[cpu_to_terminate ]), j_getPriority(computer[

cpu_to_terminate ]));

H_print(hour_to_terminate[cpu_to_terminate], flog);

34 fprintf(flog , " > Job %s (p=%d) terminato. ", j_getName(

computer[cpu_to_terminate ]), j_getPriority(computer[

cpu_to_terminate ]));

h_tmp = terminate_job(computer , hour_to_terminate , &

pc_usati , &cpu_to_terminate);

36

38 if(pc_usati == n_computer)

40 H_print(tmp ->request , stdout);

printf(" > Job %s (p=%d) acquisito. Job messo in attesa .\n",

j_getName(tmp), j_getPriority(tmp));

42 H_print(tmp ->request , flog);

fprintf(flog , " > Job %s (p=%d) acquisito. Job messo in

attesa .\n", j_getName(tmp), j_getPriority(tmp));

44

else

46

tmp_extract = q_dequeue(job_list);

48 if(tmp== tmp_extract)

50 H_print(tmp ->request , stdout);

printf(" > Job %s (p=%d) acquisito. ", j_getName(tmp),

j_getPriority(tmp));

52 H_print(tmp ->request , flog);

fprintf(flog , " > Job %s (p=%d) acquisito. ", j_getName(

tmp), j_getPriority(tmp));

54

printf("Job %s (p=%d) lanciato su pc.\n", j_getName(

127

Page 136: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

tmp_extract), j_getPriority(tmp_extract));

56 fprintf(flog , "Job %s (p=%d) lanciato su pc.\n", j_getName(

tmp_extract), j_getPriority(tmp_extract));

if(! execute_job(computer , hour_to_terminate , &pc_usati , &

cpu_to_terminate , tmp_extract , h_tmp !=NULL ? h_tmp :

tmp_extract ->request))

58

printf("ERRORE esecuzuine job.\n");

60 continue;

62 if(tmp!= tmp_extract)

64 H_print(tmp ->request , stdout);

printf(" > Job %s (p=%d) acquisito. Job messo in attesa

.\n", j_getName(tmp), j_getPriority(tmp));

66 H_print(tmp ->request , flog);

fprintf(flog , " > Job %s (p=%d) acquisito. Job messo in

attesa .\n", j_getName(tmp), j_getPriority(tmp));

68

70

while(pc_usati !=0)

72

H_print(hour_to_terminate[cpu_to_terminate], stdout);

74 printf(" > Job %s (p=%d) terminato. ", j_getName(computer[

cpu_to_terminate ]), j_getPriority(computer[cpu_to_terminate ])

);

H_print(hour_to_terminate[cpu_to_terminate], flog);

76 fprintf(flog , " > Job %s (p=%d) terminato. ", j_getName(computer

[cpu_to_terminate ]), j_getPriority(computer[cpu_to_terminate

]));

h_tmp = terminate_job(computer , hour_to_terminate , &pc_usati , &

cpu_to_terminate);

78 if(( tmp_extract = q_dequeue(job_list))!=NULL)

80 printf("Job %s (p=%d) lanciato su pc. ", j_getName(

tmp_extract), j_getPriority(tmp_extract));

fprintf(flog , "Job %s (p=%d) lanciato su pc. ", j_getName(

tmp_extract), j_getPriority(tmp_extract));

82 if(! execute_job(computer , hour_to_terminate , &pc_usati , &

cpu_to_terminate , tmp_extract , h_tmp !=NULL ? h_tmp :

tmp_extract ->request))

84 printf("ERRORE esecuzuine job.\n");

continue;

86

88 printf("\n");

fprintf(flog , "\n");

90

j_free(tmp);

92 j_free(tmp_extract);

q_free(job_list);

94 H_free(h_tmp);

fclose(fin);

96 fflush(flog);

fclose(flog);

98 return 0;

100 HOUR *terminate_job(job *computer[], HOUR *hour_to_terminate [], int *

pc_usati , int *cpu_to_terminate)

128

Page 137: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

102 HOUR *res;

j_free(computer [* cpu_to_terminate ]);

104 computer [* cpu_to_terminate] = NULL;

res = hour_to_terminate [* cpu_to_terminate ];

106 hour_to_terminate [* cpu_to_terminate] = NULL;

(* pc_usati) --;

108 int i;

*cpu_to_terminate =-1;

110 for(i=0; i<n_computer; i++)

if(computer[i]!= NULL && (* cpu_to_terminate ==-1 || H_compare(

hour_to_terminate[i], hour_to_terminate [* cpu_to_terminate ])

<0))

112 *cpu_to_terminate=i;

return res;

114

int execute_job(job *computer[], HOUR *hour_to_terminate [], int *

pc_usati , int *cpu_to_terminate , job *to_add , HOUR *actual_moment)

116

if(to_add ==NULL || actual_moment ==NULL || *pc_usati == n_computer ||

to_add ==NULL || actual_moment ==NULL)

118 return 0;

int i;

120 for(i=0; i<n_computer; i++)

122 if(computer[i]== NULL)

124 if(( hour_to_terminate[i] = H_init_by_hour(actual_moment))==

NULL)

return 0;

126 computer[i] = to_add;

H_sum(hour_to_terminate[i], computer[i]->duration);

128 if(* cpu_to_terminate ==-1)

*cpu_to_terminate=i;

130 if(H_compare(hour_to_terminate[i], hour_to_terminate [*

cpu_to_terminate ]) <0)

*cpu_to_terminate = i;

132 (* pc_usati)++;

return 1;

134

136 return 0;

Listing 11.14: Coda prioritaria - II (client.c)

1 typedef struct

3 int S;

HOUR;

5 int H_compare(HOUR *h1 , HOUR *h2);

HOUR *H_init(int h, int m, int s);

7 HOUR *H_read_by_stream(FILE *stream);

void H_print(HOUR *Hour , FILE *stream);

9 void H_free(HOUR *H);

HOUR *H_init_by_hour(HOUR *H);

11 int H_sum(HOUR *H1 , HOUR *H2); ///H1+=H2 Listing 11.15: Coda prioritaria - II (Hour.h)

1 #include <stdio.h>

#include <malloc.h>

3 #include "Hour.h"

129

Page 138: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

int H_compare(HOUR *h1 , HOUR *h2)

5

if(h1==NULL || h2==NULL)

7 return 0;

return h1 ->S - h2 ->S;;

9

HOUR *H_init(int h, int m, int s)

11

HOUR *res;

13 if(h<0 || h>=24 || m<0 || m>=60 || s<0 || s >=60)

return NULL;

15 if((res=(HOUR *) malloc(sizeof(HOUR)))==NULL)

return NULL;

17 res ->S = h*3600+m*60+s;

return res;

19

HOUR *H_read_by_stream(FILE *stream)

21

if(stream ==NULL)

23 return NULL;

int h, m, s;

25 if(fscanf(stream , "%d:%d:%d", &h, &m, &s)==4)

return H_init(h, m, s);

27 else

return NULL;

29

void H_print(HOUR *Hour , FILE *stream)

31

if(Hour==NULL || stream ==NULL)

33 return;

fprintf(stream , "%02d:%02d:%02d", (Hour ->S)/3600, (Hour ->S/60)%60,

Hour ->S%60);

35

void H_free(HOUR *H)

37

if(H==NULL)

39 return;

free(H);

41

HOUR *H_init_by_hour(HOUR *H)

43

if(H==NULL)

45 return NULL;

return H_init(H->S/3600, (H->S/60)%60, H->S%60);

47

int H_sum(HOUR *H1 , HOUR *H2)

49

if(H1==NULL || H2==NULL)

51 return 0;

H1 ->S += H2 ->S;

53 return 1;

Listing 11.16: Coda prioritaria - II (Hour.c)

#include <stdio.h>

2 #include <malloc.h>

#include <string.h>

4 #include "Hour.h"

typedef unsigned int Priority;

6 typedef struct

130

Page 139: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

8 Priority priority;

char *name;

10 HOUR *request , *duration;

job;

12 job *j_init(Priority priority , char *name , HOUR *request , HOUR *duration

);

void j_print(job *JOB , FILE *stream);

14 void j_free(job *JOB);

job *j_read_by_stream(FILE *stream);

16 job *j_read_by_string(char *string);

char *j_getName(job *JOB);

18 int j_getPriority(job *JOB); Listing 11.17: Coda prioritaria - II (job.h)

#include "job.h"

2 #define max_name_lenght 30

job *j_init(Priority priority , char *name , HOUR *request , HOUR *duration

)

4

job *res;

6 if(priority <=0 || name==NULL || request ==NULL || duration ==NULL)

return NULL;

8 if((res=(job *) malloc(sizeof(job)))==NULL)

return NULL;

10 if((res ->name=strdup(name))==NULL)

12 free(res);

return NULL;

14

res ->priority = priority;

16 res ->request = request;

res ->duration = duration;

18 return res;

20 void j_print(job *JOB , FILE *stream)

22 if(JOB==NULL || stream ==NULL)

return;

24 fprintf(stream , "%s (%d) ", JOB ->name , JOB ->priority);

H_print(JOB ->request , stream);

26 fprintf(stream , " ");

H_print(JOB ->duration , stream);

28

void j_free(job *JOB)

30

if(JOB==NULL)

32 return;

if(JOB ->name!=NULL)

34 free(JOB ->name);

if(JOB ->request !=NULL)

36 H_free(JOB ->request);

if(JOB ->duration !=NULL)

38 H_free(JOB ->duration);

free(JOB);

40

job *j_read_by_stream(FILE *stream)

42

if(stream ==NULL)

44 return NULL;

char name_tmp[max_name_lenght +1];

46 Priority priority_tmp;

131

Page 140: Appunti di 02MNONZ 1 - macisamuele.altervista.orgmacisamuele.altervista.org/IIAnno-ISemestre/Algoritmi_e_programma... · Sedgewick Robert, Algoritmi in C, Pearson, ISBN 8871921518

int hr , mr , sr , hd , md , sd;

48 if(stream == stdin)

printf("Introduci: nome priorita ’ ora_richiesta durata\n");

50 if(fscanf(stream , "%s %d %d:%d:%d %d:%d:%d", name_tmp , &priority_tmp

, &hr, &mr, &sr, &hd, &md, &sd)==8)

return j_init(priority_tmp , name_tmp , H_init(hr , mr , sr), H_init

(hd , md , sd));

52 else

return NULL;

54

job *j_read_by_string(char *string)

56

if(string ==NULL)

58 return NULL;

char name_tmp[max_name_lenght +1];

60 Priority priority_tmp;

int hr , mr , sr , hd , md , sd;

62 if(sscanf(string , "%s %d %d:%d:%d %d:%d:%d", name_tmp , &priority_tmp

, &hr, &mr, &sr, &hd, &md, &sd)==8)

return j_init(priority_tmp , name_tmp , H_init(hr , mr , sr), H_init

(hd , md , sd));

64 else

return NULL;

66

char *j_getName(job *JOB)

68

if(JOB==NULL)

70 return NULL;

return JOB ->name;

72

int j_getPriority(job *JOB)

74

if(JOB==NULL)

76 return -1;

return JOB ->priority;

78 Listing 11.18: Coda prioritaria - II (job.c)

132