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.