Capitolo 1 Array, liste ed alberi 1.1 Dato un array di n elementi con ripetizioni, sia k il numero di elementi distinti in esso contenuti. Progettare e analizzare un algoritmo che restituisca un array di k elementi contenente una e una sola volta gli elementi distinti dell’array originale. 1.2 Descrivere un algoritmo che, dati due array a e b di n e m elementi, rispettivamente, con m � n, determini se esiste un segmento di a uguale a b in tempo O(nm). 1.4 Un algoritmo di ordinamento è stabile se, in presenza di elementi uguali, ne mantiene la posizione relativa nella sequenza d’uscita (quindi gli elementi uguali appaiono contigui ma non sono permutati tra di loro): dire se gli algoritmi di ordinamento discussi nel capitolo sono stabili. Soluzioni 1.1 Sia a l’array di input, una soluzione naive consiste nel verificare, per ogni elemento a[i] di a, che a non contenga nessuna altro elemento a[j] = a[i] per j �= i. Questo induce un algoritmo di costo quadratico. Alternativamente a può essere ordinato in modo che elementi uguali siano contigui, quindi, con una semplice scansione lineare, possono essere selezionati i k elementi distinti. PA 2 Capitolo 1 – Array, liste ed alberi SelezionaDistinti( a ): Sort( a ); b[0] = a[0]; j = 1; for (i = 1; i < n; i = i+1) { if (a[i] != a[i-1]) { b[j] = a[i]; j = j+1; } } return b; Il costo dell’algoritmo è dominato dal costo dell’algoritmo Sort utilizzato per l’ordinamento. Come si vedrà questo può essere fatto in tempo O(n log n). 1.2 L’algoritmo Sottoarray verifica se b coincide col segmento di a di m caratteri che dalla posizione i. Restituisce la posizione i se tale segmento viene trovato, altrimenti restituisce −1. Sottoarray( a, b ): for (i = 0; i <= n-m; i = i+1) { j = 0; while ( j < m && a[i+j] == b[j] ) { j = j+1; } if ( j == m) { return i; } } return -1; 1.4 Consideriamo il SelectionSort, o algoritmo di ordinamento per selezione (si veda il Codice 1.2 del libro): se al passo i la sequenza a[i],..., a[n-1] contiene due elementi minimi il primo di questi verrà spostato in posizione i mentre l’altro, al passo successivo, verrà spostato in posizione i+1. Ovvero le loro posizioni relative non verranno alterate. Anche l’InsertionSort, o algoritmo per inserimento (Codice 1.3 del libro), risulta essere stabile infatti, supponiamo che al passo i ci siano due elementi di valore x a partire dalla pozione i e che il primo venga posizionato in posizione j. Quando prossimo equivale al secondo elemento di valore x, tutti gli elementi dalla pozione j+1 in poi vengono spostati destra di una pozione per far posto al “secondo” x in posizione j+1.