Laboratorio di Programmazione Appunti sulla lezione 4: Divide et impera e algoritmi di ordinamento Alessandra Raffaetà Università Ca’ Foscari Venezia Corso di Laurea in Informatica Ricerca binaria Assunzione: l’array v è ordinato. Ricerca binaria: Si confronta l’elemento x da cercare con l’elemento m in posizione centrale dell’array v. □ Se x è uguale a m ho finito. □ Se x è minore di m, la ricerca prosegue nella metà inferiore dell’array. □ Se x è maggiore di m, la ricerca prosegue nella metà superiore dell’array. Il processo prosegue fino al reperimento di x oppure fino all’esaurimento dell’array nel qual caso x non è presente in v. 1 Algoritmo per la ricerca binaria int ricercabinaria (TipoElem v[ ], TipoElem elem, int inf, int sup) { int med, indice; if (inf > sup) /*la parte del vettore fra inf e sup è vuota */ indice = -1; else { med = (inf + sup)/2; if (equal(elem, v[med])) indice = med; /*l’elemento è stato trovato */ else if (minore(elem, v[med])) /*cerca nella parte inferiore*/ indice = ricercabinaria(v, elem, inf, med -1); else /*cerca nella parte superiore*/ indice = ricercabinaria(v, elem, med+1, sup); } return indice; } Chiamata della funzione: risultato = ricercabinaria(v, elem, 0, dim–1); Esempio di ricerca binaria Dato il vettore v ordinato, determinare l’indice di 51 se occorre in v. v 7 25 33 51 55 60 0 1 2 3 4 5 7 25 33 51 55 60 0 1 2 3 4 5 51 3 51 55 4 60 med = 2 med = 4 5 med = 3 3 L’elemento è stato trovato e la sua posizione in v è 3. 2 Tecnica di progetto di algoritmi: divide et impera Soluzione ricorsiva di un problema articolata in 3 passi: Divide: divisione del problema originale in sottoproblemi analoghi a quello originale, ma di dimensione inferiore. Impera: soluzione ricorsiva dei sottoproblemi; se la dimensione dei sottoproblemi è sufficientemente piccola, questi possono essere risolti direttamente. Combina: composizione delle soluzioni dei sottoproblemi per ottenere una soluzione del problema originale. Esempio di tecnica divide et impera Problema: Trovare il minimo elemento di un array non vuoto. Divide: divide l’array A[inf..sup] in due sottoarray con metà elementi, A[inf..med] e A[med+1..sup] dove med = (inf+sup)/2. Impera: trova i min applicando la funzione ricorsivamente ai sottoarray se il sottoarray ha almeno due elementi, altrimenti il min è l’elemento stesso. Combina: confronta i due min trovati di A[inf..med] e A[med+1..sup] e restituisce il min dei due al fine di ottenere il min di A[inf..sup]. 3 Funzione massimo – divide et impera int minimo (int v[ ], int inf, int sup) /*Trova il minimo degli elementi di v di indice compreso tra inf e sup */ { int m1, m2, med; if (inf == sup) /* impera: risolve direttamente */ return v[inf]; /* divide: il problema in 2 sottopb */ med = (inf + sup)/2; m1 = minimo(v, inf, med); /*impera: trova min parte inferiore*/ m2 = minimo(v, med + 1, sup); /*impera:trova min partesuperiore*/ if (m1 < m2) /*combina: trova min del vettore*/ return m1; return m2; } Funzione conta – divide et impera Problema: Sommare gli elementi di un vettore non vuoto. int conta (int v[ ], int inf, int sup) /*restituisce la somma degli elementi nel vettore v nella porzione di array fra inf e sup */ { int med; if (inf == sup) return v[inf]; med = (inf + sup)/2; return conta(v, inf, med) + conta(v, med+1, sup); } 4 Problema dell’ordinamento Input: sequenza di N elementi <a1, …, aN> Output: permutazione <ai1,…, aiN> tale che se k < h allora minore(ak,ah). Algoritmi basati sul confronto: □ Insertion sort. □ Selection sort. □ Bubble sort. □ Merge sort. Insertion sort Algoritmo di tipo incrementale. Idea: ordinamento delle carte da gioco. Partendo con la mano sinistra vuota e le carte sul tavolo, si preleva una carta alla volta dal tavolo e si inserisce in posizione corretta nella mano sinistra (cioè mantenendo le carte in mano ordinate). ordinata ? i ordinata ? Si inserisce nel sottoarray ordinato [0..i-1] l’elemento di indice i mantenendo ordinato il sottoarray [0..i] 5 Insertion sort void insertionSort (TipoElem v[ ], int dim) { int ind_sist, /* indice del prox elemento da sistemare */ ind_contr; /* indice dell’elemento da controllare */ TipoElem val_sist; /* valore dell’elemento da sistemare */ for (ind_sist = 0; ind_sist < dim – 1; ind_sist++){ val_sist = v[ind_sist + 1]; /* controlla e sposta gli elem partendo dall’ultimo elem sistemato */ } } ind_contr = ind_sist; while (ind_contr >= 0 && maggiore(v[ind_contr], val_sist)) { v[ind_contr + 1] = v[ind_contr]; ind_contr --; } v[ind_contr + 1] = val_sist; Selection sort Idea: estrazioni successive del minimo. Si cerca il più piccolo elemento dell’array e lo si scambia con l’elemento di indice 0, quindi si cerca in [1..dim-1] il più piccolo e lo si scambia con l’elemento di indice 1 e così via. ordinata v a l m i n ordinata m i n v a l 6 Selection sort void selectionSort (TipoElem v[ ], int dim) /* indice elemento minimo */ { int i, j, i_min; TipoElem temp; for (i = 0; i < dim – 1; i++){ /* ricerca indice elemento minimo in v[i..dim-1] */ i_min = i; for (j = i+1; j < dim; j++) if (minore(v[j], v[i_min]) i_min = j; if (i != i_min) swap(v, i, i_min); } } 7