Algoritmi su Array Moreno Marzolla

Slides:



Advertisements
Presentazioni simili
Algoritmi e Strutture Dati
Advertisements

Algoritmi notevoli In linguaggio C.
Capitolo 4 Ordinamento: Selection e Insertion Sort Algoritmi e Strutture Dati.
Capitolo 4 Ordinamento: Selection e Insertion Sort Algoritmi e Strutture Dati.
Capitolo 4 Ordinamento: Selection e Insertion Sort Algoritmi e Strutture Dati.
Algoritmi e Strutture Dati
1 © Alberto Montresor Algoritmi e Strutture Dati Capitolo 7 - Tabelle hash Alberto Montresor Università di Trento This work is licensed under the Creative.
Algoritmi e Strutture Dati
Algoritmi e Strutture Dati
Algoritmi e Strutture Dati
Algoritmi e Strutture Dati
Politecnico di Milano Esercizi Preparazione alla prima prova intermedia.
Script bash I file di comandi in Linux. BASH  Bourne Again Shell  Modalità interattiva o batch (file di comandi)  Ambiente di programmazione “completo”
Tecniche Algoritmiche/1 Divide et Impera Moreno Marzolla
Statistiche d'ordine Moreno Marzolla Dip. di Scienze dell'Informazione Università di Bologna
Huffman Canonico: approfondimento. Come abbiamo visto, Huffman canonico ci permette di ottenere una decompressione più veloce e con un uso più efficiente.
1 ELEMENTI DI INFORMATICA Università degli Studi di Cagliari Corso di Laurea in Ingegneria Elettronica Linguaggio C A.A. 2011/2012
Code con priorità Moreno Marzolla Dip. di Scienze dell'Informazione Università di Bologna
Gestione della memoria
© 2007 SEI-Società Editrice Internazionale, Apogeo
Funzioni Moreno Marzolla
Linguaggio C: strutture di controllo
Progettare algoritmi veloci usando strutture dati efficienti
Introduzione al linguaggio C
Linguaggio C: Espressioni
Progettare algoritmi veloci usando strutture dati efficienti
Gli array Moreno Marzolla
Il linguaggio C Puntatori Moreno Marzolla
Il linguaggio C Strutture Moreno Marzolla
7. Strutture di controllo Ing. Simona Colucci
Logica binaria Moreno Marzolla
Ordinamento.
Divide et Impera Quicksort Mergesort Charles Antony Richard Hoare
Process synchronization
Tipo di dato: array Un array è un tipo di dato usato per memorizzare una collezione di variabili dello stesso tipo. Per memorizzare una collezione di 7.
PROGRAMMAZIONE BASH – ISTRUZIONE IF
CICLO DO – WHILE LINGUAGGIO C.
Algoritmi e Strutture Dati
Divide et Impera Quicksort Mergesort
Lezione 9 – A.A. 2016/2017 Prof. Giovanni Acampora
Java World Cicli e Array.
Programmazione e Laboratorio di Programmazione
Programmazione e Laboratorio di Programmazione
Corso Java Cicli e Array.
Programmazione e Laboratorio di Programmazione
Scrivere programmi corretti
Ordinamento in tempo lineare
© 2007 SEI-Società Editrice Internazionale, Apogeo
Programmazione e Laboratorio di Programmazione
Alberi n-ary Lezioni di C.
Progettare algoritmi veloci usando strutture dati efficienti
APPUNTI SUL LINGUAGGIO C
comprensione e modifica di codice
APPUNTI SUL LINGUAGGIO C Esercizi sugli array e strutture
La struttura dei primi programma in C
comprensione e modifica di codice
Programmazione e Laboratorio di Programmazione
Programmazione e Laboratorio di Programmazione
Fondamenti di Informatica
MergeSort Usa la tecnica del divide et impera:
concetti ed applicazioni
Lezione Terza Primi passi di programmazione
Programmazione e Laboratorio di Programmazione
Ricerca 01/08/2019 package.
HeapSort Stesso approccio incrementale del selectionSort Tipo di dato
Corso di Fondamenti di Informatica
Algoritmi di ordinamento
Programmazione e Laboratorio di Programmazione
Programmazione e Laboratorio di Programmazione
Programmazione Procedurale
Transcript della presentazione:

Algoritmi su Array Moreno Marzolla Dipartimento di Informatica—Scienza e Ingegneria (DISI) Università di Bologna http://www.moreno.marzolla.name/

Copyright © 2008, Stefano Mizzaro http://users.dimi.uniud.it/~stefano.mizzaro/dida/Prog0708/ Copyright © 2016, 2017, Moreno Marzolla http://www.moreno.marzolla.name/teaching/FINFA/ This work is licensed under the Creative Commons Attribution-Non Commercial 2.0 (CC BY-NC 2.0) License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/2.0/ or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA. Array

Ringraziamenti prof. Stefano Mizzaro, Università di Udine http://users.dimi.uniud.it/~stefano.mizzaro/ Array

Esempi classici con array Inversione Ricerca lineare Ricerca binaria Ordinamento Array

Inversione Array

Inversione di un array Scambiare di posto gli elementi di un array a[] di n elementi Il primo e l’ultimo Il secondo e il penultimo … (fermarsi a metà!!) Prima 7 12 3 -1 8 2 1 3 2 15 15 2 3 1 2 8 -1 3 12 7 Dopo Array

Inversione di un array Considero il primo e l'ultimo elemento e li scambio 7 12 3 -1 8 2 1 3 2 15 Array

Inversione di un array Considero il secondo e il penultimo elemento e li scambio 15 12 3 -1 8 2 1 3 2 7 Array

Inversione di un array ...e vado avanti così Devo però fermarmi a metà dell'array! Perché? 15 12 3 -1 8 2 1 3 2 7 Array

L’algoritmo Prima versione Considero il primo e l’ultimo e li scambio Considero il secondo e il penultimo e li scambio … Fino a metà array "Pseudo"-pseudocodice i = 0; j = n-1; while ("non sono arrivato a metà") { "scambia a[i] con a[j]" i = i + 1; j = j – 1; } Array

Raffinamento Come decido se non sono ancora arrivato a metà? i j 7 12 3 -1 8 2 1 3 2 15 i j 7 12 3 -1 8 2 1 3 2 15 i = 0; j = n-1; while (i < j) { "scambia a[i] con a[j]" i = i + 1; j = j – 1; } Array

Come (non) scambiare il valore di due variabili int a = 3, b = 5; /* modo SBAGLIATO di scambiare tra loro i valori di a e b */ a = b; b = a; Quale è il risultato del frammento di codice sopra? Array

Come scambiare il valore di due variabili 3 bicchieri, a, b e tmp ("temporaneo") In a c’è acqua, in b c’è vino, tmp è vuoto Voglio “scambiare” a e b (mettere il vino in a e l’acqua in b). Come faccio? a b tmp Array

Come scambiare il valore di due variabili 3 bicchieri, a, b e tmp ("temporaneo") In a c’è acqua, in b c’è vino, tmp è vuoto Voglio “scambiare” a e b (mettere il vino in a e l’acqua in b). Come faccio? Verso a in tmp a b tmp Array

Come scambiare il valore di due variabili 3 bicchieri, a, b e tmp ("temporaneo") In a c’è acqua, in b c’è vino, tmp è vuoto Voglio “scambiare” a e b (mettere il vino in a e l’acqua in b). Come faccio? Verso a in tmp Verso b in a a b tmp Array

Come scambiare il valore di due variabili 3 bicchieri, a, b e tmp ("temporaneo") In a c’è acqua, in b c’è vino, tmp è vuoto Voglio “scambiare” a e b (mettere il vino in a e l’acqua in b). Come faccio? Verso a in tmp Verso b in a Verso tmp in b a b tmp Array

Come scambiare il valore di due variabili /* modo CORRETTO di scambiare tra loro i valori di a e b */ int a = 3, b = 5, tmp; tmp = a; /* “verso” a in tmp */ a = b; /* “verso” b in a */ b = tmp; /* “verso” tmp in a */ Array

Come scambiare due elementi di un array Voglio “scambiare” a[i] e a[j]. Come faccio? tmp = a[i]; a[i] = a[j]; a[j] = tmp; 2. a[i] a[j] tmp 1. 3. Array

Inversione di un array /* inversione.c : inverte il contenuto di un array */ #include <stdio.h> void inverti(int a[], int n) { int i = 0, j = n-1, tmp; while ( i < j ) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; i++; j--; } #define N 10 int main( void ) int a[N], i; printf("Digita %d valori\n", N); for (i = 0; i < N; i++) { /* Lettura dell'array */ scanf("%d", &a[i]); inverti(a, N); for (i = 0; i < N; i++) { /* Stampa l'array dopo l'inversione */ printf("%d\n", a[i]); return 0; (così si legge in input un array) Array

Ricerca lineare Array

Ricerca lineare Dati Un array a[] di int La lunghezza n dell'array Un intero k int ricerca(int a[], int n, int k) Restituisce la posizione di una occorrenza di k in a[] Se k non compare in a, restituisce -1 Procedimento Scorro l’array partendo dall’inizio Fermandomi se trovo un elemento il cui valore è uguale a k, oppure se arrivo in fondo all'array k 3 7 12 3 -1 8 2 1 3 2 15 a[] Array 1 2 3 4 5 6 7 8 9

Ricerca lineare Primo tentativo (sbagliato) int ricerca(int a[], int n, int k) { int i; for (i = 0; i < n; i++) { if (a[i] == k) { "trovato" } else { "non trovato" } SBAGLIATO Con il while? k 3 a[] 7 12 3 -1 8 2 1 3 2 15 Array 1 2 3 4 5 6 7 8 9

Ricerca lineare Secondo tentativo (meglio) int ricerca(int a[], int n, int k) { int i; for (i = 0; i < n; i++) { if (a[i] == k) { "trovato" } "non trovato" OK k 3 a[] 7 12 3 -1 8 2 1 3 2 15 Array 1 2 3 4 5 6 7 8 9

Ricerca lineare /* ricerca-lineare.c */ #include <stdio.h> int ricerca(int a[], int n, int k) { int i; for (i = 0; i < n; i++) { if (a[i] == k) { return i; } return -1; int main( void ) int a[] = {7, 12, 3, -1, 8, 2, 1, 3, 2, 15}; printf("ricerca 7 = %d\n", ricerca(a, 10, 7)); printf("ricerca 15 = %d\n", ricerca(a, 10, 15)); printf("ricerca 3 = %d\n", ricerca(a, 10, 3)); printf("ricerca 17 = %d\n", ricerca(a, 10, 17)); return 0; Ricordare che l'istruzione return termina immediatamente l'esecuzione della funzione, restituendo il valore indicato Array

Una applicazione della ricerca lineare Il sindaco di Paperopoli ha deciso di tassare i residenti in base al reddito. Detto R il reddito lordo annuo, l'importo dovuto in tasse è (R ´ x), dove x dipende da R secondo la seguente tabella Se 0 ≤ R < 10000 → x = 0.05 Se 10000 ≤ R < 22000 → x = 0.11 Se 22000 ≤ R → x = 0.15 Scrivere un programma in C che chiede all'utente di inserire il reddito R (tipo double; se l'utente inserisce un valore negativo, richiederlo), e stampa l'importo dovuto in tasse Array

Primo tentativo: funziona, ma... /* tasse-1.c */ #include <stdio.h> int main( void ) { double R, x; do { printf("Inserire reddito R\n"); scanf("%lf", &R); } while (R < 0); if ( R < 10000.0) { x = 0.05; } else { if ( R < 22000.0 ) { x = 0.11; x = 0.15; } printf("Le tasse dovute ammontano a %f\n", R*x); return 0; Array

Un bel giorno... Vista la situazione disastrata delle finanze di Paperopoli, il sindaco decide di introdurre nuovi scaglioni: Se 0 ≤ R < 10000 → x = 0.05 Se 10000 ≤ R < 22000 → x = 0.11 Se 22000 ≤ R < 35000 → x = 0.15 Se 35000 ≤ R < 45000 → x = 0.17 Se 45000 ≤ R < 57000 → x = 0.20 Se 57000 ≤ R → x = 0.25 Modificare il programma precedente per funzionare correttamente nella nuova situazione Array

/* tasse-2.c */ #include <stdio.h> int main( void ) { double R, x; do { printf("Inserire reddito R\n"); scanf("%lf", &R); } while (R < 0); if ( R < 10000.0) { x = 0.05; } else { if ( R < 22000.0 ) { x = 0.11; if ( R < 35000.0 ) { x = 0.15; if ( R < 45000.0 ) { x = 0.17; if ( R < 57000.0 ) { x = 0.20; x = 0.25; } printf("Le tasse dovute ammontano a %f\n", R*x); return 0; Array

/* tasse-2.c */ #include <stdio.h> int main( void ) { double R, x; do { printf("Inserire reddito R\n"); scanf("%lf", &R); } while (R < 0); if ( R < 10000.0) { x = 0.05; } else { if ( R < 22000.0 ) { x = 0.11; if ( R < 35000.0 ) { x = 0.15; if ( R < 45000.0 ) { x = 0.17; if ( R < 57000.0 ) { x = 0.20; x = 0.25; } printf("Le tasse dovute ammontano a %f\n", R*x); return 0; Array

Idea Memorizzo gli scaglioni e le relative percentuali in una "tabella" Dato il reddito R, cerco nella "tabella" lo scaglione corrispondente e da questo ricava la percentuale Se gli estremi degli scaglioni e/o le percentuali cambiano, devo cambiare solo la tabella e non il programma che fa la ricerca! Array

Nuova soluzione: meglio /* tasse-3.c */ #include <stdio.h> int main( void ) { const int nscaglioni = 6; double scaglioni[] = { 0.0, 10000.0, 22000.0, 35000.0, 45000.0, 57000.0}; double imposta[] = {0.05, 0.11, 0.15, 0.17, 0.20, 0.25}; double R, x; int i; do { printf("Inserire reddito R\n"); scanf("%lf", &R); } while (R < 0); for (i=0; (i < nscaglioni) && (R >= scaglioni[i]); i++) { x = imposta[i]; } printf("Le tasse dovute ammontano a %f (imposta=%f%%)\n", R*x, x*100); return 0; scaglioni[i] è il limite inferiore dello scaglione i-esimo (inizio a contare da i = 0). imposta[i] è la percentuale di tasse per i redditi appartenenti allo scaglione i-esimo Array

Esercizio 6 cassetti di resistenze etichettati con i seguenti valori (in Ohm): 10, 15, 22, 33, 47, 68 I valori hanno una tolleranza di +/- 10% Significa. ad es., che il cassetto etichettato 15 può contenere resistenze con 15 ´ 0.9 ≤ R ≤ 15 ´ 1.1 Nota: gli intervalli NON si sovrappongono Data una resistenza di valore misurato R, determinare in quale cassetto deve essere riposta E' possibile che R sia tale da non poter essere inserito in alcun cassetto; in tal caso il programma lo deve segnalare ad es. con un opportuno messaggio d'errore Assumere che tutti i valori siano di tipo float Array

10 15 22 33 47 68 R = 21 Array

Possibile soluzione /* resistenza.c */ #include <stdio.h> int main( void ) { const int n = 6; /* numero di cassetti */ float val[] = {10, 15, 22, 33, 47, 68}; float R; int i; printf("Inserire R\n"); scanf("%f", &R); for (i=0; i<n; i++) { if ( R >= val[i]*0.9 && R <= val[i]*1.1 ) break; } if ( i < n ) { printf("Resistenza R=%f nel cassetto etichettato %f\n", R, val[i]); } else { printf("Resistenza R=%f non inseribile in alcun cassetto\n", R); return 0; Array

Ricerca Binaria Array

Ricerca binaria Dati: Un array di valori reali distinti v[0], v[1], … v[n-1] ordinati in senso crescente (v[0] < v[1] < … < v[n-1]) Un valore reale k (arbitrario) Determinare la posizione di k nell'array (se presente) Cioè determinare l'indice i, se esiste, tale che v[i] == k Se k non compare nell'array, restituire -1 Es: v[0] v[1] v[2] v[3] v[4] v[5] v[6] v[7] Cerchiamo k = 13 -3 -1 2 5 6 13 15 21 Array La funzione restituisce 5 Vedere i lucidi sugli algoritmi

Funzionamento dell'algoritmo Usiamo due valori interi i (inizio) e f (fine) per rappresentare la posizione (indice) del primo e dell'ultimo elemento della porzione di array in cui potrebbe trovarsi il valore cercato Indichiamo con m (mezzo) l'indice dell'elemento che occupa la posizione centrale nel sottovettore v[i] … v[f] i=0 m=3 f=6 v[0] v[1] v[2] v[3] v[4] v[5] v[6] 2 3 7 12 18 21 27 Cerchiamo k = 3 Algoritmi

Pseudocodice i = 0; f = n – 1; while (f ≥ i) { m = (i + f) / 2; if (v[m] == k) { "trovato in posizione m" } else { if (v[m] > k) { f = m – 1; i = m + 1; } "non trovato" Algoritmi

/* ricerca-binaria.c */ #include <stdio.h> int ricbinaria(int v[], int n, int k) { int i = 0, f = n-1, m; while (f >= i) { m = (i + f) / 2; if (v[m] == k) { return m; /* trovato in posizione m */ } else { if (v[m] > k) { f = m - 1; i = m + 1; } return -1; /* non trovato */ int main( void ) int a[] = {-1, 1, 2, 3, 7, 15, 16, 18, 20, 21}; printf("ricerca 7 = %d\n", ricbinaria(a, 10, 7)); printf("ricerca -1 = %d\n", ricbinaria(a, 10, -1)); printf("ricerca 17 = %d\n", ricbinaria(a, 10, 17)); printf("ricerca -2 = %d\n", ricbinaria(a, 10, -2)); return 0; Algoritmi

Cosa succede se l'array contiene valori duplicati? /* ricerca-binaria.c */ #include <stdio.h> int ricbinaria(int v[], int n, int k) { int i = 0, f = n-1, m; while (f >= i) { m = (i + f) / 2; if (v[m] == k) { return m; /* trovato in posizione m */ } else { if (v[m] > k) { f = m - 1; i = m + 1; } return -1; /* non trovato */ int main( void ) int a[] = {-1, 1, 2, 3, 7, 15, 16, 18, 20, 21}; printf("ricerca 7 = %d\n", ricbinaria(a, 10, 7)); printf("ricerca -1 = %d\n", ricbinaria(a, 10, -1)); printf("ricerca 17 = %d\n", ricbinaria(a, 10, 17)); printf("ricerca -2 = %d\n", ricbinaria(a, 10, -2)); return 0; Cosa succede se la funzione ricbinaria() viene invocata su un array vuoto (n = 0)? Cosa succede se l'array contiene valori duplicati? Algoritmi

Ordinamento Algoritmi

Ordinamento Ordinare un array Problema classico Capita spesso in moltissime applicazioni Vari algoritmi Ne vediamo uno (Selection Sort) Semplice da capire Non molto efficiente Array

Algoritmi e Strutture Dati Selection Sort 12 7 3 2 14 22 1 3 1 7 3 2 14 22 12 3 Cerco il minimo in a[0]...a[n-1] e lo scambio con a[0] Cerco il minimo in a[1]...a[n-1] e lo scambio con a[1] ... Cerco il minimo in a[i]...a[n-1] e lo scambio con a[i] 1 2 3 7 14 22 12 3 1 2 3 7 14 22 12 3 1 2 3 3 14 22 12 7 1 2 3 3 7 22 12 14 1 2 3 3 7 12 22 14 Algoritmi e Strutture Dati 1 2 3 3 7 12 14 22

Algoritmi e Strutture Dati Pseudocodice Prima versione Raffinamento for i ← 0 to n – 2 do "Determina il valore minimo v[j] del sottovettore v[i] .. .v[n – 1]" "Scambia v[i] con v[j]" endfor for i ← 0 to n–2 do for j ← i+1 to n–1 do if (a[i] > a[j]) then "scambia a[i] con a[j]" endif endfor Algoritmi e Strutture Dati

Algoritmi e Strutture Dati 12 7 3 2 14 22 1 3 i j 7 12 3 2 14 22 1 3 3 12 7 2 14 22 1 3 2 12 7 3 14 22 1 3 2 12 7 3 14 22 1 3 2 12 7 3 14 22 1 3 1 12 7 3 14 22 2 3 Algoritmi e Strutture Dati

Algoritmi e Strutture Dati Costo computazionale Quante volte viene eseguito il blocco di codice evidenziato? for i ← 0 to n–2 do for j ← i+1 to n–1 do if (a[i] > a[j]) then "scambia a[i] con a[j]" endif endfor Il blocco viene eseguito (n-1) + (n-2) + … + 2 + 1 volte Algoritmi e Strutture Dati

Algoritmi e Strutture Dati = una iterazione del ciclo "for" interno (quello con indice j) n - 1 i → 1 2 3 4 n-2 Algoritmi e Strutture Dati

Algoritmi e Strutture Dati = una iterazione del ciclo "for" interno (quello con indice j) n - 1 n n - 1 i → 1 2 3 4 n-2 Algoritmi e Strutture Dati

Il codice /* selection-sort.c */ #include <stdio.h> void selectionsort(int a[], int n) { int i, j, tmp; for (i = 0; i < n - 1; i++) { for (j = i + 1; j < n; j++) { if (a[i] > a[j]) { tmp = a[i]; /* scambio a[i] con a[j] */ a[i] = a[j]; a[j] = tmp; } #define N 10 int main( void ) int a[N], i; for (i = 0; i < N; i++) { scanf(“%d”, &a[i]); } selectionsort(a, N); for (i = 0; i < N; i++) { printf(“%d\n”, a[i]); } return 0; Array