INFORMATICA Algoritmi fondamentali Riordinamento di un vettore • Il problema del riordinamento di un vettore è frequente e talvolta condiziona addirittura le prestazioni di un programma. • La prima idea che viene in mente è quella di ricostruire il vettore in un altro vettore inserendo i dati uno dopo l’altro nell’ordine richiesto (ascendente o discendente). • Generalmente però i vettori sono così grandi da non poter essere “duplicati” in memoria: il riordinamento dunque deve essere effettuato all’interno del vettore stesso senza ausilio di altre strutture dati. © Piero Demichelis 2 Riordinamento di un vettore • Il problema di trovare un algoritmo efficiente dipende dal fatto che il numero di confronti che devono essere eseguiti tra gli elementi del vettore può essere così grande da rendere il programma inefficiente. • Una prima idea per risolvere il problema potrebbe essere quella di cercare il massimo (o il minimo) dell’intero vettore, portarlo in prima posizione scambiandolo con l’elemento che attualmente la occupa, poi ripetere l’operazione considerando tutti gli elementi tranne il primo, e così via fino alla penultina posizione. • Questo algoritmo è noto col nome di selection sort . © Piero Demichelis 3 Riordinamento di un vettore: esempio • Realizzare un programma che legge da tastiera una sequenza di 10 numeri interi e li salva in un vettore. Successivamente li riordina dal più piccolo al più grande senza uso di altre strutture dati, e infine li visualizza. • Analisi: - dopo aver letto i 10 valori da tastiera (mediante un semplice ciclo for) dobbiamo trovare un algoritmo che ci permetta di riorganizzare il nostro vettore scambiando di posizione i vari elementi in modo da riordinarli; © Piero Demichelis 4 Riordinamento con selection sort • Utilizziamo come algoritmo di riordinamento quello che abbiamo appena enunciato e noto col nome di selection sort. • Pseudocodice: - Sia n il numero di elementi del vettore vett; - con un indice i che va da 0 a n-1: /* definisce il vettore dentro cui cercare il minimo (inizia da i e finisce a n) */ • inizializza min col valore di vett[i]; • inizializza ind = i; • con un indice j che va da i+1 a n: /* cerca il minimo del vettore */ - se vett[j] < min: /* se l’elemento attuale è < del minimo */ · min = vett[j]; /* lo salva come nuovo minimo */ · ind = j; /* memorizza l’indice in cui si trova */ • scambia l’elemento di indice i con l’elemento di indice j. © Piero Demichelis 5 Riordinamento con selection sort #include <stdio.h> #include <conio.h> #define lmax 10 /* Funzione riordina: riordina un vettore di interi lungo n */ void riordina (int vett[ ], int n) /* prototipo della funzione */ main() { int vett [lmax], ind, i; clrscr(); © Piero Demichelis 6 Riordinamento con selection sort ind = 0; printf ("Introduci i valori\n"); while (ind < lmax) /* legge gli elementi del vettore */ { printf ("\nElemento di indice %d: ", ind); scanf ("%d", &vett[ind]); ind++; } riordina (vett, ind); /* riordina il vettore */ printf ("\n Vettore riordinato \n"); /* visualizza il vettore riordinato */ for (i = 0; i < ind; i++) printf ("%d\n", vett[i]); } © Piero Demichelis 7 Riordinamento con selection sort void riordina (int vett[ ], int n) /* funzione di riordino */ { int min, ind, i, j; for (i = 0; i < n-1; i++) /* definisce il vettore in cui cercare il min. */ { min = vett[i]; /* inizializzazioni per ogni nuovo “sottovettore” */ ind = i; for (j = i + 1; j < n; j++) /* cerca il minimo del “sottovettore” */ if (vett[j] < min) { min = vett[j]; ind = j; } vett[ind] = vett[i]; /* scambia il primo elemento del “sottovettore” */ vett[i] = min; /* con l’elemento minimo appena trovato */ } } © Piero Demichelis 8 Riordinamento con bubble sort • L’algoritmo di riordinamento più interessante è però quello noto col nome di bubble sort. Si può dimostrare che questo è l’algoritmo di riordinamento che mediamente usa il minor numero di confronti fra gli elementi del vettore. • Pseudocodice: - Sia n il numero di elementi del vettore vett; - inizializza una variabile logica (inordine) a FALSO; - finché non ho finito (ovvero inordine è FALSO): • ipotizza che vett sia ordinato (inordine = VERO) • con un indice i che va dal primo al penultimo elemento: - confronto: se vett[i] > vett[i+1] : · scambia i due elementi tra loro; · assegna a inordine il valore FALSO (fatto uno scambio). © Piero Demichelis 9 Riordinamento con bubble sort #include <stdio.h> #define NELEM 10 #define FALSO 0 #define VERO 1 /* Funzione bubble: riordina un vettore di interi lungo n */ void bubble (int vett[ ], int n); © Piero Demichelis /* prototipo */ 10 Riordinamento con bubble sort main( ) { int vett [NELEM], ind; printf ("Introduci i valori\n"); for (ind = 0; ind < NELEM; ind++) { /* riempie il vettore con nelem numeri interi */ printf ("\nElemento di indice %d: ", ind); scanf ("%d", &vett[ind]); } bubble (vett, NELEM); /* riordina il vettore */ printf ("\n Vettore riordinato \n"); /* visualizza il vettore riordinato */ for (ind = 0; ind < NELEM; ind++) printf ("%d\n", vett[ind]); } © Piero Demichelis 11 Riordinamento con bubble sort void bubble (int vett[ ], int n) { int provv, i, inordine; inordine = FALSO; /* inizializza inordine a FALSO */ while (!inordine) /* Finché il vettore non è ordinato */ { inordine = VERO; /* ipotizza che sia ordinato, cioè di aver finito */ for (i = 0; i < (n - 1); i++) /* i va dal primo al penultimo elem. */ if (vett[i] > vett[i+1]) /* se quello che segue è più grande */ { provv = vett[i]; /* scambia i due elementi tra loro */ vett[i] = vett[i+1]; vett[i+1] = provv; inordine = FALSO; /* è stato fatto uno scambio! */ } } } © Piero Demichelis 12 Riordinamento alfabetico • Realizzare un programma che legge da tastiera una sequenza di nomi (10), li riordina in ordine alfabetico mediante l'algoritmo di bubble-sort e infine li visualizza. • Analisi: - il problema è identico al precedente ma occorre considerare il fatto che i nomi sono delle stringhe; - bisogna pertanto modificare la funzione bubble nella definizione, quando esegue il confronto fra i due elementi del vettore e quando scambia fra di loro gli elementi. © Piero Demichelis 13 Riordinamento alfabetico #include <stdio.h> #define #define #define #define NELEM 10 LUNGMAX 50 FALSO 0 VERO 1 /* Funzione bubble: riordina un vettore di stringhe lungo n */ void bubble (char vett[ ][LUNGMAX], int n) © Piero Demichelis /* prototipo */ 14 Riordinamento alfabetico main( ) { char parole [NELEM][LUNGMAX]; int ind; printf ("Introduci le parole\n"); for (ind = 0; ind < NELEM; ind++) { /* Riempie il vettore con NELEM parole */ printf ("\nParola di indice %d: ", ind); scanf ("%s", parole[ind]); } bubble (parole, NELEM); /* Riordina il vettore */ printf ("\n Vettore riordinato \n"); /* Visualizza il vettore riordinato */ for (ind = 0; ind < ind; ind++) printf ("%s\n", parole[ind]); } © Piero Demichelis 15 Riordinamento alfabetico void bubble(char vett[ ][LUNGMAX], int n) { int i, inordine; char provv[LUNGMAX]; inordine = FALSO; /* inizializza inordine a FALSO */ while (!inordine) /* Finché il vettore non è ordinato */ { inordine = VERO; /* ipotizza che sia ordinato, cioè di aver finito */ for (i = 0; i < (n - 1); i++) /* i va dal primo al penultimo elem. */ if (strcmp (vett[i], vett[i+1]) > 0) /* se quello che segue è > */ { strcpy (provv, vett[i]); /* scambia i due elementi tra loro */ strcpy (vett[i], vett[i+1]); strcpy (vett[i+1], provv); inordine = FALSO; } /* è stato fatto uno scambio! */ } } © Piero Demichelis 16 Ricerca dicotomica • La ricerca di un elemento in un vettore può essere molto laboriosa in termini di tempo di esecuzione. • Se la base dati è molto grande è opportuno minimizzare questo tempo riducendo il numero di confronti tramite un semplice algoritmo detto di ricerca dicotomica. • Il vettore deve essere dapprima riordinato, poi si confronta l’elemento posto a metà vettore (indice = n/2) con l’elemento cercato. Si hanno 3 possibilità: a) é quello cercato; b) l’elemento cercato è più grande; c) l’elemento cercato è più piccolo. • Se l’elemento cercato è più grande si considera un nuovo vettore formato dalla sola seconda metà dell’intero vettore e si ricomincia la ricerca col confronto tra elemento cercato e elemento posto a metà del nuovo vettore; e così via. © Piero Demichelis 17 Ricerca dicotomica #include <stdio.h> #include <conio.h> #define MAX_DATI 100 #define FALSE 0 #define VERO 1 /* prototipo delle funzioni di ricerca e di riordinamento int trovato (int vett[ ], int elemento, int *p_posiz, int n_dati); void bubble (int vett[ ], int n); */ main() { int num_dati, dato, indice, p_posiz, cercato; int vett [MAX_DATI]; clrscr(); © Piero Demichelis 18 Ricerca dicotomica indice = 0; printf ("\nIntroduci il vettore, premi <ctrl>+z per finire\n"); while (((scanf ("%d",&dato)) != EOF) && (indice < MAX_DATI)) { /* legge numeri fino a EOF oppure a MAX_DATI */ vett [indice] = dato; indice++; } num_dati = indice; /* in num_dati numero di dati letti */ bubble (vett, num_dati); /* riordina il vettore di interi */ printf (“\nVettore riordinato:”); /* visualizza il vettore riordinato for (indice = 0; indice < num_dati; indice++) printf (“\nElemento di indice %d = %d”, indice, vett [indice]); © Piero Demichelis */ 19 Ricerca dicotomica /* richiede il dato da cercare printf ("\nQuale dato vuoi cercare? "); scanf ("%d", &cercato); */ /* cerca il dato con la funzione trovato che restituisce col suo nome un valore logico (vero o falso) a seconda che il dato sia presente o meno nel vettore e, se presente, l’indice del dato nella variabile p_posiz */ if ( trovato (vett, cercato, &p_posiz, num_dati) ) printf ("\nDato presente in posizione %d", p_posiz); else printf ("\nDato non presente"); } © Piero Demichelis 20 Ricerca dicotomica int trovato (int vett[ ], int dato, int *p_posiz, int n_dati) { int meta, limite_inf, limite_sup; int presente; limite_inf = 0; /* indice inferiore della porzione di vettore */ limite_sup = n_dati - 1; /* indice superiore della porzione di vettore */ presente = FALSE; while ((!presente) && (limite_inf <= limite_sup)) { meta = (limite_sup + limite_inf) / 2; /* confronto il dato cercato con l’elemento di metà del vettore */ if (vett[meta] == dato) presente = TRUE; /* è lui, finito! */ © Piero Demichelis 21 Ricerca dicotomica else { /* non è lui, procedo usando il metodo di bisezione if (vett[meta] > dato) limite_sup = meta - 1; else limite_inf = meta + 1; */ } } *p_posiz = meta; return (presente); } © Piero Demichelis 22 Riordinamento con bubble sort void bubble (int vett[ ], int n) { int provv, i, inordine; inordine = FALSE; /* inizializza inordine a FALSE */ while (!inordine) /* Finché il vettore non è ordinato */ { inordine = TRUE; /* ipotizza che sia ordinato, cioè di aver finito */ for (i = 0; i < (n - 1); i++) /* i va dal primo al penultimo elem. */ if (vett[i] > vett[i+1]) /* se quello che segue è più grande */ { provv = vett[i]; /* scambia i due elementi tra loro */ vett[i] = vett[i+1]; vett[i+1] = provv; inordine = FALSE; /* è stato fatto uno scambio! */ } } } © Piero Demichelis 23