Tempo: 120 minuti
1. Modificare l’algoritmo Selection Sort in modo che,
dati un array di interi A e un intero k < A.length,
l’algoritmo modificato restituisca il valore del k-esimo
elemento (in ordine crescente) presente in A.
Esempio:
se A = {23, 3, 11, 4, 15, 5} e k = 2 il valore da
restituire e’ 4. Stimare la complessita’ dell’algoritmo
nel caso peggiore.
Sol. un algoritmo che realizza l’operazione richiesta e’
il seguente:
int kselection(int A[], int k) {
int minIndex = 0; /* memorizza indice del minimo corrente
*/
int temp = 0;
for (int i=0; i<k; i++) {
minIndex = i;
for (int j=i+1; j<n; j++) /* Cerca (i+1)-esimo
elemento */
if (A[minIndex]>A[j])
minIndex = j;
/* Elemento in pos. minIndex e’ (i+1)-esimo
elemento.
Scambialo con A[i] */
temp = A[i];
A[i] = A[minIndex]; /* minIndex indice dell’iesimo el. */
A[minIndex] = temp;
}
return A[k-1];
}
Per il calcolo della complessita’ si puo’ osservare
quanto segue: i) il ciclo for esterno e’ eseguito k
volte; ii) per ogni valore di i, il ciclo interno e’
eseguito n-i volte. Una prima approssimazione del costo
dell’algoritmo e’ dunque O(kn), perche’ n-i<n. Una stima
piu’ precisa si ottiene sommando i contributi delle
diverse iterazioni del ciclo piu’ interno. Si ha:
k
k(k + 1)
c o st o  c (n  i)  ckn - c
 O kn - k 2 ,
2
i1
dove la costante c tiene conto delle istruzioni eseguite
nel ciclo for piu’ interno, delle inizializzazioni ecc.

2. Il tipo astratto DoppioStack e’ consente le seguenti
operazioni:
- headPush(): inserimento in testa.
tailPush(): inserimento in coda.
headPop(): rimozione e restituzione dell’elemento in
testa.
- tailPop(): rimozione e restituzione dell’ elemento
in testa.
- top(): restituzione (senza rimozione) dell’elemento
in testa.
- bottom():restituzione
(senza
rimozione)
dell’elemento in coda.
Si implementi in Java tale tipo per oggetti generici,
usando LinkedList e garantendo l’aderenza del tipo
implementato a quello astratto.
Sol. si veda la soluzione dell’esercizio n. 3 della parte
2.
-
3. Considerato l’ADT BST dalle classi BSTNode e BSTTree
cosi’ fatte:
public class BSTNode {
private Comparable key;
BSTNode left, right; /* figli */
/* Costruttori */
public void visit() { key.visit(); }
public boolean isLeaf() {…}
public Comparable key() {return key;}
}
public class BSTTree {
private BSTNode root;
/* altre variabili di classe */
/* Costruttori */
public root() {return root;}
public void insert(Comparable el) {…}
public void delete(Comparable el){…}
public BSTNode search (Comparable el) {…}
/* altri metodi */
}
Scrivere un metodo BSTNode max() della classe BSTTree,
che restituisce il nodo avente chiave massima.
Sol. il nodo in questione e’ quello piu’ a destra.
Dunque:
public BSTNode max() {
BSTNode temp = root();
if (temp = null) /* Albero vuoto */
return temp;
while (temp.right != null)
temp = temp.right;
return temp;
}
4. Si consideri un heap minimale a chiavi intere H dotato
delle consuete operazioni insert(int k), deleteMin(),
getMin(). Mostrare come esso puo’ essere usato per
ordinare un array A di n interi in tempo asintoticamente
ottimo.
Sol. E’ sufficiente inserire gli elementi di A in H e poi
eseguire n estrazioni del minimo. Cio’ puo’ essere
ottenuto nel modo seguente:
for (i=0; i<n; i++)
H.insert(A[i]);
for (i=0; i<n; i++)
A[i] = H.deleteMin();
Si osservi che il costo di questo algoritmo e’ O(nlog2n).
Il motivo e’ che ciascun inserimento/cancellazione ha
costo O(log2n) nel caso peggiore e abbiamo n inserimenti
ed n cancellazioni.
5. Si scrivano le classi necessarie a implementare grafi
non diretti, con pesi interi sugli archi, con al piu’ N
nodi e rappresentati mediante matrice di adiacenza. La
classe che rappresenta il grafo deve implementare, tra le
altre, le operazioni di inserimento e rimozione di archi.
Sol. si definisce innanzi tutto una classe Arco, che
rappresenta il generico arco tra due nodi:
public class Arco {
String etichetta; /* Es.: per assegnare identificatori
agli archi */
int peso;
public Arco(String e, int p) {
etichetta = e;
peso = p;
}
public Arco() {
eitchetta = null;
peso = 0;
}
}
A questo punto possiamo definire la classe Grafo:
public Grafo {
private Arco[][] mioGrafo;
private static final int N = 100; /* No. Max. di vertici
*/
/* Costruttore */
public Grafo() {
mioGrafo = new Arco[N][N];
/* Inizialmente il grafo e’ vuoto */
for (int i=0; i<N ; i++)
for (int j=0; j<N; j++)
A[i][j] = null;
}
/* Metodi */
public void insert(Arco a, int i, int j) {
/* Inserisce arco tra vertici di indici i e j */
mioGrafo[i][j] = a;
return;
}
public Arco remove(int i, int j) {
/* Rimuove e restituisce l’arco tra i vertici i e j
*/
Arco temp = null;
temp = mioGrafo[i][j];
mioGrafo[i][j] = null;
return temp;
}
/* Altri metodi */
} /* Fine della classe Grafo */